00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
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
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
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
00269 }
00270 }
00271 }
00272
00273 bool DashelInterface::attemptToReconnect()
00274 {
00275 assert(stream == 0);
00276 try
00277 {
00278
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
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
00363 connect(&dashelInterface, SIGNAL(messageAvailable(Message *)), SLOT(messageFromDashel(Message *)), Qt::QueuedConnection);
00364 connect(&dashelInterface, SIGNAL(dashelDisconnection()), SLOT(disconnectionFromDashel()), Qt::QueuedConnection);
00365
00366
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
00398 for (NodesMap::const_iterator node = nodes.begin(); node != nodes.end(); ++node)
00399 {
00400
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
00441 nodeIt->second.debugBytecode = bytecode;
00442 nodeIt->second.eventAddressToId = bytecode.getEventAddressesToIds();
00443
00444
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
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
00725
00726
00727
00728 descriptionManager.processMessage(message);
00729
00730
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
00743
00744 }
00745 else
00746 {
00747 (this->*(messageHandler->second))(message);
00748 }
00749
00750
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
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
00847
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
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
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
00923
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
00969 NodesMap::const_iterator nodeIt = nodes.find(node);
00970
00971 if (nodeIt == nodes.end())
00972 return -1;
00973
00974
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
00985 NodesMap::const_iterator nodeIt = nodes.find(node);
00986
00987 if (nodeIt == nodes.end())
00988 return -1;
00989
00990
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
01004 break;
01005 case Dashel::DashelException::ConnectionFailed:
01006
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 }