DashelTarget.cpp
Go to the documentation of this file.
00001 /*
00002         Aseba - an event-based framework for distributed robot control
00003         Copyright (C) 2007--2012:
00004                 Stephane Magnenat <stephane at magnenat dot net>
00005                 (http://stephane.magnenat.net)
00006                 and other contributors, see authors.txt for details
00007         
00008         This program is free software: you can redistribute it and/or modify
00009         it under the terms of the GNU Lesser General Public License as published
00010         by the Free Software Foundation, version 3 of the License.
00011         
00012         This program is distributed in the hope that it will be useful,
00013         but WITHOUT ANY WARRANTY; without even the implied warranty of
00014         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015         GNU Lesser General Public License for more details.
00016         
00017         You should have received a copy of the GNU Lesser General Public License
00018         along with this program. If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 #include "DashelTarget.h"
00022 #include "../msg/msg.h"
00023 #include "../utils/utils.h"
00024 #include <algorithm>
00025 #include <iostream>
00026 #include <ostream>
00027 #include <sstream>
00028 #include <cassert>
00029 #include <QInputDialog>
00030 #include <QtGui>
00031 #include <QLibraryInfo>
00032 #include <stdexcept>
00033 
00034 
00035 #include <DashelTarget.moc>
00036 
00037 #ifdef WIN32 // for Sleep
00038 #include <windows.h>
00039 #endif
00040 
00041 namespace Aseba
00042 {
00043         using std::copy;
00044         using namespace Dashel;
00045 
00048         
00049         DashelConnectionDialog::DashelConnectionDialog()
00050         {
00051                 typedef std::map<int, std::pair<std::string, std::string> > PortsMap;
00052                 const PortsMap ports = SerialPortEnumerator::getPorts();
00053                 
00054                 QSettings settings;
00055                 unsigned sectionEnabled(settings.value("connection dialog enabled group", 0).toUInt());
00056                 if ((sectionEnabled == 1) && (ports.size() == 0))
00057                         sectionEnabled = 0;
00058                 
00059                 QVBoxLayout* mainLayout = new QVBoxLayout(this);
00060                 
00061                 netGroupBox = new QGroupBox(tr("Network (TCP)"));
00062                 netGroupBox->setCheckable(true);
00063                 netGroupBox->setChecked(sectionEnabled == 0);
00064                 QGridLayout* netLayout = new QGridLayout;
00065                 netLayout->addWidget(new QLabel(tr("Host")), 0, 0);
00066                 netLayout->addWidget(new QLabel(tr("Port")), 0, 1);
00067                 host = new QLineEdit(settings.value("tcp host", ASEBA_DEFAULT_HOST).toString());
00068                 netLayout->addWidget(host, 1, 0);
00069                 port = new QSpinBox();
00070                 port->setMinimum(0);
00071                 port->setMaximum(65535);
00072                 port->setValue(settings.value("tcp port", ASEBA_DEFAULT_PORT).toInt());
00073                 netLayout->addWidget(port, 1, 1);
00074                 netGroupBox->setLayout(netLayout);
00075                 connect(netGroupBox, SIGNAL(clicked()), SLOT(netGroupChecked()));
00076                 mainLayout->addWidget(netGroupBox);
00077                 
00078                 serialGroupBox = new QGroupBox(tr("Serial"));
00079                 serialGroupBox->setCheckable(true);
00080                 QHBoxLayout* serialLayout = new QHBoxLayout();
00081                 serial = new QListWidget();
00082                 bool serialPortSet(false);
00083                 for (PortsMap::const_iterator it = ports.begin(); it != ports.end(); ++it)
00084                 {
00085                         const QString text(it->second.second.c_str());
00086                         QListWidgetItem* item = new QListWidgetItem(text);
00087                         item->setData(Qt::UserRole, QVariant(QString::fromUtf8(it->second.first.c_str())));
00088                         serial->addItem(item);
00089                         if (settings.value("serial name") == text)
00090                         {
00091                                 serial->setCurrentItem(item);
00092                                 serialPortSet = true;
00093                         }
00094                 }
00095                 if (sectionEnabled == 1 && !serialPortSet)
00096                         sectionEnabled = 2;
00097                 serialGroupBox->setChecked(sectionEnabled == 1);
00098                 serial->setSelectionMode(QAbstractItemView::SingleSelection);
00099                 serialLayout->addWidget(serial);
00100                 connect(serial, SIGNAL(itemSelectionChanged()), SLOT(setupOkStateFromListSelection()));
00101                 serialGroupBox->setLayout(serialLayout);
00102                 connect(serialGroupBox, SIGNAL(clicked()), SLOT(serialGroupChecked()));
00103                 mainLayout->addWidget(serialGroupBox);
00104                 
00105                 customGroupBox = new QGroupBox(tr("Custom"));
00106                 customGroupBox->setCheckable(true);
00107                 customGroupBox->setChecked(sectionEnabled == 2);
00108                 QHBoxLayout* customLayout = new QHBoxLayout();
00109                 custom = new QLineEdit(settings.value("custom target", ASEBA_DEFAULT_TARGET).toString());
00110                 customLayout->addWidget(custom);
00111                 customGroupBox->setLayout(customLayout);
00112                 connect(customGroupBox, SIGNAL(clicked()), SLOT(customGroupChecked()));
00113                 mainLayout->addWidget(customGroupBox);
00114                 
00115                 languageSelectionBox = new QComboBox;
00116                 languageSelectionBox->addItem(QString::fromUtf8("English"), "en");
00117                 languageSelectionBox->addItem(QString::fromUtf8("Français"), "fr");
00118                 languageSelectionBox->addItem(QString::fromUtf8("Deutsch"), "de");
00119                 languageSelectionBox->addItem(QString::fromUtf8("Español"), "es");
00120                 //qDebug() << "locale is " << QLocale::system().name();
00121                 for (int i = 0; i < languageSelectionBox->count(); ++i)
00122                 {
00123                         if (QLocale::system().name().startsWith(languageSelectionBox->itemData(i).toString()))
00124                         {
00125                                 languageSelectionBox->setCurrentIndex(i);
00126                                 break;
00127                         }
00128                 }
00129                 mainLayout->addWidget(languageSelectionBox);
00130                 
00131                 QHBoxLayout* buttonLayout = new QHBoxLayout();
00132                 connectButton = new QPushButton(QIcon(":/images/ok.png"), tr("Connect"));
00133                 connect(connectButton, SIGNAL(clicked(bool)), SLOT(accept()));
00134                 buttonLayout->addWidget(connectButton);
00135                 QPushButton* cancelButton = new QPushButton(QIcon(":/images/no.png"), tr("Cancel"));
00136                 connect(cancelButton, SIGNAL(clicked(bool)), SLOT(reject()));
00137                 buttonLayout->addWidget(cancelButton);
00138                 mainLayout->addLayout(buttonLayout);
00139                 
00140                 setWindowTitle(tr("Aseba Target Selection"));
00141         }
00142         
00143         std::string DashelConnectionDialog::getTarget()
00144         {
00145                 QSettings settings;
00146                 if (netGroupBox->isChecked())
00147                 {
00148                         settings.setValue("connection dialog enabled group", 0);
00149                         settings.setValue("tcp host", host->text());
00150                         settings.setValue("tcp port", port->value());
00151                         std::ostringstream oss;
00152                         oss << "tcp:host=" << host->text().toLocal8Bit().constData() << ";port=" << port->value();
00153                         return oss.str();
00154                 }
00155                 else if (serialGroupBox->isChecked())
00156                 {
00157                         const QItemSelectionModel* model(serial->selectionModel());
00158                         assert(model && !model->selectedRows().isEmpty());
00159                         const QModelIndex item(model->selectedRows().first());
00160                         settings.setValue("connection dialog enabled group", 1);
00161                         settings.setValue("serial name", item.data());
00162                         QString target("ser:device=%0");
00163                         return target.arg(item.data(Qt::UserRole).toString()).toLocal8Bit().constData();
00164                 }
00165                 else if (customGroupBox->isChecked())
00166                 {
00167                         settings.setValue("connection dialog enabled group", 2);
00168                         settings.setValue("custom target", custom->text());
00169                         return custom->text().toLocal8Bit().constData();
00170                 }
00171                 else
00172                 {
00173                         assert(false);
00174                         return "";
00175                 }
00176         }
00177         
00178         QString DashelConnectionDialog::getLocaleName()
00179         {
00180                 return languageSelectionBox->itemData(languageSelectionBox->currentIndex()).toString();
00181         }
00182         
00183         void DashelConnectionDialog::netGroupChecked()
00184         {
00185                 netGroupBox->setChecked(true);
00186                 serialGroupBox->setChecked(false);
00187                 customGroupBox->setChecked(false);
00188                 setupOkStateFromListSelection();
00189         }
00190         
00191         void DashelConnectionDialog::serialGroupChecked()
00192         {
00193                 netGroupBox->setChecked(false);
00194                 serialGroupBox->setChecked(true);
00195                 customGroupBox->setChecked(false);
00196                 setupOkStateFromListSelection();
00197         }
00198         
00199         void DashelConnectionDialog::customGroupChecked()
00200         {
00201                 netGroupBox->setChecked(false);
00202                 serialGroupBox->setChecked(false);
00203                 customGroupBox->setChecked(true);
00204                 setupOkStateFromListSelection();
00205         }
00206         
00207         void DashelConnectionDialog::setupOkStateFromListSelection()
00208         {
00209                 connectButton->setEnabled(serial->selectionModel()->hasSelection() || (!serialGroupBox->isChecked()));
00210         }
00211         
00212         
00213         DashelInterface::DashelInterface(QVector<QTranslator*> translators, const QString& commandLineTarget) :
00214                 isRunning(true),
00215                 stream(0)
00216         {
00217                 // first use local name
00218                 const QString& systemLocale(QLocale::system().name());
00219                 translators[0]->load(QString("qt_") + systemLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
00220                 translators[1]->load(QString(":/asebastudio_") + systemLocale);
00221                 translators[2]->load(QString(":/compiler_") + systemLocale);
00222                 
00223                 // try to connect to cammand line target, if any
00224                 DashelConnectionDialog targetSelector;
00225                 if (!commandLineTarget.isEmpty())
00226                 {
00227                         bool failed = false;
00228                         try
00229                         {
00230                                 const std::string& testTarget(commandLineTarget.toStdString());
00231                                 stream = Hub::connect(testTarget);
00232                                 lastConnectedTarget = testTarget;
00233                         }
00234                         catch (DashelException e)
00235                         {
00236                                 // exception, try again
00237                                 failed = true;
00238                         }
00239                         
00240                         if (failed)
00241                                 QMessageBox::warning(0, tr("Connection to command line target failed"), tr("Cannot connect to target %0").arg(commandLineTarget));
00242                         else
00243                                 return;
00244                 }
00245                 // show connection dialog
00246                 while (true)
00247                 {
00248                         if (targetSelector.exec() == QDialog::Rejected)
00249                         {
00250                                 throw std::runtime_error("connection dialog closed");
00251                         }
00252                         
00253                         try
00254                         {
00255                                 //qDebug() << "Connecting to " << targetSelector.getTarget().c_str();
00256                                 const std::string& testTarget(targetSelector.getTarget());
00257                                 stream = Hub::connect(testTarget);
00258                                 lastConnectedTarget = testTarget;
00259                                 assert(translators.size() == 3);
00260                                 language = targetSelector.getLocaleName();
00261                                 translators[0]->load(QString("qt_") + language, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
00262                                 translators[1]->load(QString(":/asebastudio_") + language);
00263                                 translators[2]->load(QString(":/compiler_") + language);
00264                                 break;
00265                         }
00266                         catch (DashelException e)
00267                         {
00268                                 // exception, try again
00269                         }
00270                 }
00271         }
00272         
00273         bool DashelInterface::attemptToReconnect()
00274         {
00275                 assert(stream == 0);
00276                 try
00277                 {
00278                         // we have to stop hub because otherwise it will be forever in poll()
00279                         stream = Hub::connect(lastConnectedTarget);
00280                         Dashel::Hub::stop();
00281                         if (stream)
00282                                 return true;
00283                 }
00284                 catch (DashelException e)
00285                 {
00286                 }
00287                 return false;
00288         }
00289         
00290         
00291         void DashelInterface::stop()
00292         {
00293                 isRunning = false;
00294                 Dashel::Hub::stop();
00295         }
00296         
00297         // In QThread main function, we just make our Dashel hub switch listen for incoming data
00298         void DashelInterface::run()
00299         {
00300                 while (isRunning)
00301                         Dashel::Hub::run();
00302         }
00303         
00304         void DashelInterface::incomingData(Stream *stream)
00305         {
00306                 Message *message = Message::receive(stream);
00307                 emit messageAvailable(message);
00308         }
00309         
00310         void DashelInterface::connectionClosed(Stream* stream, bool abnormal)
00311         {
00312                 Q_UNUSED(stream);
00313                 Q_UNUSED(abnormal);
00314                 emit dashelDisconnection();
00315                 Q_ASSERT(stream == this->stream);
00316                 this->stream = 0;
00317         }
00318         
00319         void SignalingDescriptionsManager::nodeProtocolVersionMismatch(const std::string &nodeName, uint16 protocolVersion)
00320         {
00321                 if (protocolVersion > ASEBA_PROTOCOL_VERSION)
00322                 {
00323                         QMessageBox::warning(0,
00324                                 QApplication::tr("Protocol version mismatch"),
00325                                 QApplication::tr("Aseba Studio uses an older protocol (%1) than node %0 (%2), please upgrade Aseba Studio.").arg(QString::fromUtf8(nodeName.c_str())).arg(ASEBA_PROTOCOL_VERSION).arg(protocolVersion)
00326                         );
00327                 }
00328                 else if (protocolVersion < ASEBA_PROTOCOL_VERSION)
00329                 {
00330                         QMessageBox::warning(0,
00331                                 QApplication::tr("Protocol version mismatch"),
00332                                 QApplication::tr("Node %0 uses an older protocol (%2) than Aseba Studio (%1), please upgrade the node firmware.").arg(QString::fromUtf8(nodeName.c_str())).arg(ASEBA_PROTOCOL_VERSION).arg(protocolVersion)
00333                         );
00334                 }
00335         }
00336         
00337         void SignalingDescriptionsManager::nodeDescriptionReceived(unsigned nodeId)
00338         {
00339                 emit nodeDescriptionReceivedSignal(nodeId);
00340         }
00341         
00342         
00343         enum InNextState
00344         {
00345                 NOT_IN_NEXT,
00346                 WAITING_INITAL_PC,
00347                 WAITING_LINE_CHANGE
00348         };
00349         
00350         DashelTarget::Node::Node()
00351         {
00352                 executionMode = EXECUTION_UNKNOWN;
00353         }
00354         
00355         DashelTarget::DashelTarget(QVector<QTranslator*> translators, const QString& commandLineTarget) :
00356                 dashelInterface(translators, commandLineTarget),
00357                 writeBlocked(false)
00358         {
00359                 userEventsTimer.setSingleShot(true);
00360                 connect(&userEventsTimer, SIGNAL(timeout()), SLOT(updateUserEvents()));
00361                 
00362                 // we connect the events from the stream listening thread to slots living in our gui thread
00363                 connect(&dashelInterface, SIGNAL(messageAvailable(Message *)), SLOT(messageFromDashel(Message *)), Qt::QueuedConnection);
00364                 connect(&dashelInterface, SIGNAL(dashelDisconnection()), SLOT(disconnectionFromDashel()), Qt::QueuedConnection);
00365                 
00366                 // we also connect to the description manager to know when we have a new node available
00367                 connect(&descriptionManager, SIGNAL(nodeDescriptionReceivedSignal(unsigned)), SLOT(nodeDescriptionReceived(unsigned)));
00368                 
00369                 messagesHandlersMap[ASEBA_MESSAGE_DISCONNECTED] = &Aseba::DashelTarget::receivedDisconnected;
00370                 messagesHandlersMap[ASEBA_MESSAGE_VARIABLES] = &Aseba::DashelTarget::receivedVariables;
00371                 messagesHandlersMap[ASEBA_MESSAGE_ARRAY_ACCESS_OUT_OF_BOUNDS] = &Aseba::DashelTarget::receivedArrayAccessOutOfBounds;
00372                 messagesHandlersMap[ASEBA_MESSAGE_DIVISION_BY_ZERO] = &Aseba::DashelTarget::receivedDivisionByZero;
00373                 messagesHandlersMap[ASEBA_MESSAGE_EVENT_EXECUTION_KILLED] = &Aseba::DashelTarget::receivedEventExecutionKilled;
00374                 messagesHandlersMap[ASEBA_MESSAGE_NODE_SPECIFIC_ERROR] = &Aseba::DashelTarget::receivedNodeSpecificError;
00375                 messagesHandlersMap[ASEBA_MESSAGE_EXECUTION_STATE_CHANGED] = &Aseba::DashelTarget::receivedExecutionStateChanged;
00376                 messagesHandlersMap[ASEBA_MESSAGE_BREAKPOINT_SET_RESULT] = &Aseba::DashelTarget::receivedBreakpointSetResult;
00377                 messagesHandlersMap[ASEBA_MESSAGE_BOOTLOADER_ACK] = &Aseba::DashelTarget::receivedBootloaderAck;
00378 
00379                 dashelInterface.start();
00380         }
00381         
00382         DashelTarget::~DashelTarget()
00383         {
00384                 dashelInterface.stop();
00385                 dashelInterface.wait();
00386                 DashelTarget::disconnect();
00387         }
00388         
00389         void DashelTarget::disconnect()
00390         {
00391                 assert(writeBlocked == false);
00392                 
00393                 if (dashelInterface.stream)
00394                 {
00395                         try
00396                         {
00397                                 // detach all nodes
00398                                 for (NodesMap::const_iterator node = nodes.begin(); node != nodes.end(); ++node)
00399                                 {
00400                                         //DetachDebugger(node->first).serialize(dashelInterface.stream);
00401                                         BreakpointClearAll(node->first).serialize(dashelInterface.stream);
00402                                         Run(node->first).serialize(dashelInterface.stream);
00403                                 }
00404                                 dashelInterface.stream->flush();
00405                         }
00406                         catch(Dashel::DashelException e)
00407                         {
00408                                 handleDashelException(e);
00409                         }
00410                 }
00411         }
00412         
00413         const TargetDescription * const DashelTarget::getDescription(unsigned node) const
00414         {
00415                 return descriptionManager.getDescription(node);
00416         }
00417         
00418         void DashelTarget::broadcastGetDescription()
00419         {
00420                 if (writeBlocked || !dashelInterface.stream) return;
00421                 
00422                 try
00423                 {
00424                         GetDescription().serialize(dashelInterface.stream);
00425                         dashelInterface.stream->flush();
00426                 }
00427                 catch(Dashel::DashelException e)
00428                 {
00429                         handleDashelException(e);
00430                 }
00431         }
00432         
00433         void DashelTarget::uploadBytecode(unsigned node, const BytecodeVector &bytecode)
00434         {
00435                 if (writeBlocked || !dashelInterface.stream) return;
00436                 
00437                 NodesMap::iterator nodeIt = nodes.find(node);
00438                 assert(nodeIt != nodes.end());
00439                 
00440                 // fill debug bytecode and build address map
00441                 nodeIt->second.debugBytecode = bytecode;
00442                 nodeIt->second.eventAddressToId = bytecode.getEventAddressesToIds();
00443                 
00444                 // send bytecode
00445                 try
00446                 {
00447                         sendBytecode(dashelInterface.stream, node, std::vector<uint16>(bytecode.begin(), bytecode.end()));
00448                         dashelInterface.stream->flush();
00449                 }
00450                 catch(Dashel::DashelException e)
00451                 {
00452                         handleDashelException(e);
00453                 }
00454         }
00455         
00456         void DashelTarget::writeBytecode(unsigned node)
00457         {
00458                 if (writeBlocked || !dashelInterface.stream) return;
00459                 
00460                 try
00461                 {
00462                         WriteBytecode(node).serialize(dashelInterface.stream);
00463                         dashelInterface.stream->flush();
00464                 }
00465                 catch(Dashel::DashelException e)
00466                 {
00467                         handleDashelException(e);
00468                 }
00469         }
00470         
00471         void DashelTarget::reboot(unsigned node)
00472         {
00473                 if (writeBlocked || !dashelInterface.stream) return;
00474                 
00475                 try
00476                 {
00477                         Reboot(node).serialize(dashelInterface.stream);
00478                         dashelInterface.stream->flush();
00479                 }
00480                 catch(Dashel::DashelException e)
00481                 {
00482                         handleDashelException(e);
00483                 }
00484         }
00485         
00486         void DashelTarget::sendEvent(unsigned id, const VariablesDataVector &data)
00487         {
00488                 if (writeBlocked || !dashelInterface.stream) return;
00489                 
00490                 try
00491                 {
00492                         UserMessage(id, data).serialize(dashelInterface.stream);
00493                         dashelInterface.stream->flush();
00494                 }
00495                 catch(Dashel::DashelException e)
00496                 {
00497                         handleDashelException(e);
00498                 }
00499         }
00500         
00501         void DashelTarget::setVariables(unsigned node, unsigned start, const VariablesDataVector &data)
00502         {
00503                 if (writeBlocked || !dashelInterface.stream) return;
00504                 
00505                 try
00506                 {
00507                         SetVariables(node, start, data).serialize(dashelInterface.stream);
00508                         dashelInterface.stream->flush();
00509                 }
00510                 catch(Dashel::DashelException e)
00511                 {
00512                         handleDashelException(e);
00513                 }
00514         }
00515         
00516         void DashelTarget::getVariables(unsigned node, unsigned start, unsigned length)
00517         {
00518                 if (writeBlocked || !dashelInterface.stream) return;
00519                 
00520                 const unsigned variablesPayloadSize = ASEBA_MAX_EVENT_ARG_COUNT-1;
00521 
00522                 try
00523                 {
00524                         while (length > variablesPayloadSize)
00525                         {
00526                                 GetVariables(node, start, variablesPayloadSize).serialize(dashelInterface.stream);
00527                                 start += variablesPayloadSize;
00528                                 length -= variablesPayloadSize;
00529                         }
00530 
00531                         GetVariables(node, start, length).serialize(dashelInterface.stream);
00532                         dashelInterface.stream->flush();
00533                 }
00534                 catch(Dashel::DashelException e)
00535                 {
00536                         handleDashelException(e);
00537                 }
00538         }
00539         
00540         void DashelTarget::reset(unsigned node)
00541         {
00542                 if (writeBlocked || !dashelInterface.stream) return;
00543                 
00544                 try
00545                 {
00546                         Reset(node).serialize(dashelInterface.stream);
00547                         dashelInterface.stream->flush();
00548                 }
00549                 catch(Dashel::DashelException e)
00550                 {
00551                         handleDashelException(e);
00552                 }
00553         }
00554         
00555         void DashelTarget::run(unsigned node)
00556         {
00557                 if (writeBlocked || !dashelInterface.stream) return;
00558                 
00559                 NodesMap::iterator nodeIt = nodes.find(node);
00560                 assert(nodeIt != nodes.end());
00561                 
00562                 try
00563                 {
00564                         if (nodeIt->second.executionMode == EXECUTION_STEP_BY_STEP)
00565                                 Step(node).serialize(dashelInterface.stream);
00566                         Run(node).serialize(dashelInterface.stream);
00567                         dashelInterface.stream->flush();
00568                 }
00569                 catch(Dashel::DashelException e)
00570                 {
00571                         handleDashelException(e);
00572                 }
00573         }
00574         
00575         void DashelTarget::pause(unsigned node)
00576         {
00577                 if (writeBlocked || !dashelInterface.stream) return;
00578                 
00579                 try
00580                 {
00581                         Pause(node).serialize(dashelInterface.stream);
00582                         dashelInterface.stream->flush();
00583                 }
00584                 catch(Dashel::DashelException e)
00585                 {
00586                         handleDashelException(e);
00587                 }
00588         }
00589         
00590         void DashelTarget::next(unsigned node)
00591         {
00592                 if (writeBlocked || !dashelInterface.stream) return;
00593                 
00594                 NodesMap::iterator nodeIt = nodes.find(node);
00595                 assert(nodeIt != nodes.end());
00596                 
00597                 nodeIt->second.steppingInNext = WAITING_INITAL_PC;
00598                 
00599                 GetExecutionState getExecutionStateMessage;
00600                 getExecutionStateMessage.dest = node;
00601                 
00602                 try
00603                 {
00604                         getExecutionStateMessage.serialize(dashelInterface.stream);
00605                         dashelInterface.stream->flush();
00606                 }
00607                 catch(Dashel::DashelException e)
00608                 {
00609                         handleDashelException(e);
00610                 }
00611         }
00612         
00613         void DashelTarget::stop(unsigned node)
00614         {
00615                 if (writeBlocked || !dashelInterface.stream) return;
00616                 
00617                 try
00618                 {
00619                         Stop(node).serialize(dashelInterface.stream);
00620                         dashelInterface.stream->flush();
00621                 }
00622                 catch(Dashel::DashelException e)
00623                 {
00624                         handleDashelException(e);
00625                 }
00626         }
00627         
00628         void DashelTarget::setBreakpoint(unsigned node, unsigned line)
00629         {
00630                 if (writeBlocked || !dashelInterface.stream) return;
00631                 
00632                 int pc = getPCFromLine(node, line);
00633                 if (pc >= 0)
00634                 {
00635                         BreakpointSet breakpointSetMessage;
00636                         breakpointSetMessage.pc = pc;
00637                         breakpointSetMessage.dest = node;
00638                         
00639                         try
00640                         {
00641                                 breakpointSetMessage.serialize(dashelInterface.stream);
00642                                 dashelInterface.stream->flush();
00643                         }
00644                         catch(Dashel::DashelException e)
00645                         {
00646                                 handleDashelException(e);
00647                         }
00648                 }
00649         }
00650         
00651         void DashelTarget::clearBreakpoint(unsigned node, unsigned line)
00652         {
00653                 if (writeBlocked || !dashelInterface.stream) return;
00654                 
00655                 int pc = getPCFromLine(node, line);
00656                 if (pc >= 0)
00657                 {
00658                         BreakpointClear breakpointClearMessage;
00659                         breakpointClearMessage.pc = pc;
00660                         breakpointClearMessage.dest = node;
00661                         
00662                         try
00663                         {
00664                                 breakpointClearMessage.serialize(dashelInterface.stream);
00665                                 dashelInterface.stream->flush();
00666                         }
00667                         catch(Dashel::DashelException e)
00668                         {
00669                                 handleDashelException(e);
00670                         }
00671                 }
00672         }
00673         
00674         void DashelTarget::clearBreakpoints(unsigned node)
00675         {
00676                 if (writeBlocked || !dashelInterface.stream) return;
00677                 
00678                 BreakpointClearAll breakpointClearAllMessage;
00679                 breakpointClearAllMessage.dest = node;
00680                 
00681                 try
00682                 {
00683                         breakpointClearAllMessage.serialize(dashelInterface.stream);
00684                         dashelInterface.stream->flush();
00685                 }
00686                 catch(Dashel::DashelException e)
00687                 {
00688                         handleDashelException(e);
00689                 }
00690         }
00691         
00692         void DashelTarget::blockWrite()
00693         {
00694                 writeBlocked = true;
00695         }
00696         
00697         void DashelTarget::unblockWrite()
00698         {
00699                 writeBlocked = false;
00700         }
00701         
00702         void DashelTarget::updateUserEvents()
00703         {
00704                 // send only 20 latest user events
00705                 if (userEventsQueue.size() > 20)
00706                         emit userEventsDropped(userEventsQueue.size() - 20);
00707                 while (userEventsQueue.size() > 20)
00708                 {
00709                         delete userEventsQueue.head();
00710                         userEventsQueue.dequeue();
00711                 }
00712                 
00713                 while (!userEventsQueue.isEmpty())
00714                 {
00715                         emit userEvent(userEventsQueue.head()->type, userEventsQueue.head()->data);
00716                         delete userEventsQueue.head();
00717                         userEventsQueue.dequeue();
00718                 }
00719         }
00720         
00721         void DashelTarget::messageFromDashel(Message *message)
00722         {
00723                 bool deleteMessage = true;
00724                 //message->dump(std::cout);
00725                 //std::cout << std::endl;
00726                 
00727                 // let the description manager filter the message
00728                 descriptionManager.processMessage(message);
00729                 
00730                 // see if we have a registered handler for this message
00731                 MessagesHandlersMap::const_iterator messageHandler = messagesHandlersMap.find(message->type);
00732                 if (messageHandler == messagesHandlersMap.end())
00733                 {
00734                         UserMessage *userMessage = dynamic_cast<UserMessage *>(message);
00735                         if (userMessage)
00736                         {
00737                                 userEventsQueue.enqueue(userMessage);
00738                                 if (!userEventsTimer.isActive())
00739                                         userEventsTimer.start(50);
00740                                 deleteMessage = false;
00741                         }
00742                         /*else
00743                                 qDebug() << QString("Unhandeled non user message of type 0x%0 received from %1").arg(message->type, 6).arg(message->source);*/
00744                 }
00745                 else
00746                 {
00747                         (this->*(messageHandler->second))(message);
00748                 }
00749                 
00750                 // if required, garbage collect this message
00751                 if (deleteMessage)
00752                         delete message;
00753         }
00754         
00755         struct ReconnectionDialog: public QMessageBox
00756         {
00757                 ReconnectionDialog(DashelInterface& dashelInterface):
00758                         dashelInterface(dashelInterface)
00759                 {
00760                         setWindowTitle(tr("Aseba Studio - Connection closed"));
00761                         setText(tr("Warning, connection closed: I am trying to reconnect."));
00762                         setStandardButtons(QMessageBox::Cancel);
00763                         setEscapeButton(QMessageBox::Cancel);
00764                         setIcon(QMessageBox::Warning);
00765                         
00766                         startTimer(1000);
00767                 }
00768         
00769         protected:
00770                 virtual void timerEvent ( QTimerEvent * event )
00771                 {
00772                         if (dashelInterface.attemptToReconnect())
00773                                 accept();
00774                 }
00775                 
00776                 DashelInterface& dashelInterface;
00777         };
00778         
00779         void DashelTarget::disconnectionFromDashel()
00780         {
00781                 emit networkDisconnected();
00782                 nodes.clear();
00783                 descriptionManager.reset();
00784                 
00785                 // show a dialog box that is trying to reconnect
00786                 ReconnectionDialog reconnectionDialog(dashelInterface);
00787                 reconnectionDialog.exec();
00788         }
00789         
00790         void DashelTarget::nodeDescriptionReceived(unsigned nodeId)
00791         {
00792                 Node& node = nodes[nodeId];
00793                 
00794                 node.steppingInNext = NOT_IN_NEXT;
00795                 node.lineInNext = 0;
00796                 
00797                 emit nodeConnected(nodeId);
00798         }
00799         
00800         void DashelTarget::receivedVariables(Message *message)
00801         {
00802                 Variables *variables = polymorphic_downcast<Variables *>(message);
00803                 emit variablesMemoryChanged(variables->source, variables->start, variables->variables);
00804         }
00805         
00806         void DashelTarget::receivedArrayAccessOutOfBounds(Message *message)
00807         {
00808                 ArrayAccessOutOfBounds *aa = polymorphic_downcast<ArrayAccessOutOfBounds *>(message);
00809                 
00810                 int line = getLineFromPC(aa->source, aa->pc);
00811                 if (line >= 0)
00812                 {
00813                         emit arrayAccessOutOfBounds(aa->source, line, aa->size, aa->index);
00814                         emit executionModeChanged(aa->source, EXECUTION_STOP);
00815                 }
00816         }
00817         
00818         void DashelTarget::receivedDivisionByZero(Message *message)
00819         {
00820                 DivisionByZero *dz = polymorphic_downcast<DivisionByZero *>(message);
00821                 
00822                 int line = getLineFromPC(dz->source, dz->pc);
00823                 if (line >= 0)
00824                 {
00825                         emit divisionByZero(dz->source, line);
00826                         emit executionModeChanged(dz->source, EXECUTION_STOP);
00827                 }
00828         }
00829         
00830         void DashelTarget::receivedEventExecutionKilled(Message *message)
00831         {
00832                 EventExecutionKilled *eek = polymorphic_downcast<EventExecutionKilled *>(message);
00833                 
00834                 int line = getLineFromPC(eek->source, eek->pc);
00835                 if (line >= 0)
00836                 {
00837                         emit eventExecutionKilled(eek->source, line);
00838                 }
00839         }
00840         
00841         void DashelTarget::receivedNodeSpecificError(Message *message)
00842         {
00843                 NodeSpecificError *nse = polymorphic_downcast<NodeSpecificError *>(message);
00844                 
00845                 int line = getLineFromPC(nse->source, nse->pc);
00846                 // The NodeSpecificError can be triggered even if the pc is not valid
00847 //              if (line >= 0)
00848 //              {
00849                         emit nodeSpecificError(nse->source, line, QString::fromStdWString(nse->message));
00850                         emit executionModeChanged(nse->source, EXECUTION_STOP);
00851 //              }
00852         }
00853         
00854         void DashelTarget::receivedExecutionStateChanged(Message *message)
00855         {
00856                 ExecutionStateChanged *ess = polymorphic_downcast<ExecutionStateChanged *>(message);
00857                 
00858                 Node &node = nodes[ess->source];
00859                 int line = getLineFromPC(ess->source, ess->pc);
00860                 
00861                 assert(writeBlocked == false);
00862                 assert(dashelInterface.stream);
00863                 
00864                 Target::ExecutionMode mode;
00865                 if (ess->flags & ASEBA_VM_STEP_BY_STEP_MASK)
00866                 {
00867                         if (ess->flags & ASEBA_VM_EVENT_ACTIVE_MASK)
00868                         {
00869                                 mode = EXECUTION_STEP_BY_STEP;
00870                                 if (line >= 0)
00871                                 {
00872                                         // Step by step, manage next
00873                                         if (node.steppingInNext == NOT_IN_NEXT)
00874                                         {
00875                                                 emit executionPosChanged(ess->source, line);
00876                                                 emit executionModeChanged(ess->source, mode);
00877                                                 emit variablesMemoryEstimatedDirty(ess->source);
00878                                         }
00879                                         else if (node.steppingInNext == WAITING_INITAL_PC)
00880                                         {
00881                                                 // we have line, do steps now
00882                                                 node.lineInNext = line;
00883                                                 node.steppingInNext = WAITING_LINE_CHANGE;
00884                                                 
00885                                                 try
00886                                                 {
00887                                                         Step(ess->source).serialize(dashelInterface.stream);
00888                                                         dashelInterface.stream->flush();
00889                                                 }
00890                                                 catch(Dashel::DashelException e)
00891                                                 {
00892                                                         handleDashelException(e);
00893                                                 }
00894                                         }
00895                                         else if (node.steppingInNext == WAITING_LINE_CHANGE)
00896                                         {
00897                                                 if (
00898                                                         (node.eventAddressToId.find(ess->pc) != node.eventAddressToId.end()) ||
00899                                                         (line != static_cast<int>(node.lineInNext))
00900                                                 )
00901                                                 {
00902                                                         node.steppingInNext = NOT_IN_NEXT;
00903                                                         emit executionPosChanged(ess->source, line);
00904                                                         emit executionModeChanged(ess->source, mode);
00905                                                         emit variablesMemoryEstimatedDirty(ess->source);
00906                                                 }
00907                                                 else
00908                                                 {
00909                                                         try
00910                                                         {
00911                                                                 Step(ess->source).serialize(dashelInterface.stream);
00912                                                                 dashelInterface.stream->flush();
00913                                                         }
00914                                                         catch(Dashel::DashelException e)
00915                                                         {
00916                                                                 handleDashelException(e);
00917                                                         }
00918                                                 }
00919                                         }
00920                                         else
00921                                                 assert(false);
00922                                         // we can safely return here, all case that require
00923                                         // emitting signals have been handeled
00924                                         node.executionMode = mode;
00925                                         return;
00926                                 }
00927                         }
00928                         else
00929                         {
00930                                 mode = EXECUTION_STOP;
00931                         }
00932                 }
00933                 else
00934                 {
00935                         mode = EXECUTION_RUN;
00936                 }
00937                 
00938                 emit executionModeChanged(ess->source, mode);
00939                 if (node.executionMode != mode)
00940                 {
00941                         emit variablesMemoryEstimatedDirty(ess->source);
00942                         node.executionMode = mode;
00943                 }
00944         }
00945         
00946         void DashelTarget::receivedDisconnected(Message *message)
00947         {
00948                 Disconnected *disconnected = polymorphic_downcast<Disconnected *>(message);
00949                 
00950                 emit nodeDisconnected(disconnected->source);
00951         }
00952         
00953         void DashelTarget::receivedBreakpointSetResult(Message *message)
00954         {
00955                 BreakpointSetResult *bsr = polymorphic_downcast<BreakpointSetResult *>(message);
00956                 unsigned node = bsr->source;
00957                 emit breakpointSetResult(node, getLineFromPC(node, bsr->pc), bsr->success);
00958         }
00959         
00960         void DashelTarget::receivedBootloaderAck(Message *message)
00961         {
00962                 BootloaderAck *ack = polymorphic_downcast<BootloaderAck*>(message);
00963                 emit bootloaderAck(ack->errorCode, ack->errorAddress);
00964         }
00965         
00966         int DashelTarget::getPCFromLine(unsigned node, unsigned line)
00967         {
00968                 // first lookup node
00969                 NodesMap::const_iterator nodeIt = nodes.find(node);
00970                 
00971                 if (nodeIt == nodes.end())
00972                         return -1;
00973                 
00974                 // then find PC
00975                 for (size_t i = 0; i < nodeIt->second.debugBytecode.size(); i++)
00976                         if (nodeIt->second.debugBytecode[i].line == line)
00977                                 return i;
00978                 
00979                 return -1;
00980         }
00981         
00982         int DashelTarget::getLineFromPC(unsigned node, unsigned pc)
00983         {
00984                 // first lookup node
00985                 NodesMap::const_iterator nodeIt = nodes.find(node);
00986                 
00987                 if (nodeIt == nodes.end())
00988                         return -1;
00989                 
00990                 // then get line
00991                 if (pc < nodeIt->second.debugBytecode.size())
00992                         return nodeIt->second.debugBytecode[pc].line;
00993                 
00994                 return -1;
00995         }
00996 
00997         void DashelTarget::handleDashelException(Dashel::DashelException e)
00998         {
00999                 switch(e.source)
01000                 {
01001                 case Dashel::DashelException::ConnectionLost:
01002                 case Dashel::DashelException::IOError:
01003                         // "normal" disconnections, managed internally in Dashel::Hub, so don't care about
01004                         break;
01005                 case Dashel::DashelException::ConnectionFailed:
01006                         // should not happen here, but can because of typos in Dashel, catch it for now
01007                         break;
01008                 default:
01009                         QMessageBox::critical(NULL, tr("Unexpected Dashel Error"), tr("A communication error happened:") + " (" + QString::number(e.source) + ") " + e.what());
01010                         break;
01011                 }
01012         }
01013         
01015 }


aseba
Author(s): Stéphane Magnenat
autogenerated on Sun Oct 5 2014 23:46:38