source: flair-src/branches/mavlink/tools/FlairGCS/src/Manager.cpp @ 46

Last change on this file since 46 was 30, checked in by Sanahuja Guillaume, 5 years ago

show rx rate in GCS

File size: 9.8 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5#include "Manager.h"
6#include "UdtSocket.h"
7#include "ConnectionLayout.h"
8#include "communication.h"
9#include <QDate>
10#include <QFileDialog>
11#include <QMessageBox>
12#include <QPushButton>
13#include <QTabBar>
14#include <QTimer>
15#include <QThread>
16#include <QTextStream>
17#include <QVBoxLayout>
18#include <QModelIndex>
19//#include <qmetatype.h>
20#include <qendian.h>
21#include <iostream>
22#include <string>
23#include <fstream>
24#include <stdio.h>
25
26#ifndef WIN32
27#include <arpa/inet.h>
28#else
29#include <winsock2.h>
30#include <ws2tcpip.h>
31#endif
32
33using namespace std;
34
35Manager::Manager(QString name, int port) : QWidget() {
36  qRegisterMetaType<QModelIndex>("QModelIndex"); // pour le file ui??
37  this->name = name;
38
39  setWindowTitle(name);
40//statusBar()->showMessage(tr("Ready to serve"));
41  // manager layout
42  managerLayout = new QVBoxLayout;
43  setLayout(managerLayout);
44
45  // tab bar for multiple connections
46  tabBar = new QTabBar();
47  managerLayout->addWidget(tabBar);
48  connect(tabBar, SIGNAL(currentChanged(int)), this,
49          SLOT(tabBarCurrentChanged(int)));
50  currentTab = 0;
51
52  // layout boutons
53  button_layout = new QGridLayout();
54  managerLayout->addLayout(button_layout);
55
56  // boutons du button_Layout
57  send_button = new QPushButton("apply all");
58  reset_button = new QPushButton("reset all");
59  load_button = new QPushButton("load all locally");
60  save_button = new QPushButton("save all locally");
61  button_layout->addWidget(send_button, 0, 0);
62  button_layout->addWidget(reset_button, 0, 1);
63  button_layout->addWidget(load_button, 0, 2);
64  button_layout->addWidget(save_button, 0, 3);
65
66  connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
67  connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
68  connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
69  connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
70
71  status=new QStatusBar();
72  status->setSizeGripEnabled(false);
73  button_layout->addWidget(status, 1,0);
74
75  UDT::startup();
76  serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
77
78  // for non blocking accept
79  bool blocking = false;
80  UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
81
82  sockaddr_in my_addr;
83  my_addr.sin_family = AF_INET;
84  my_addr.sin_port = htons(port);
85  my_addr.sin_addr.s_addr = INADDR_ANY;
86  memset(&(my_addr.sin_zero), '\0', 8);
87
88  if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
89    printf("bind error, %s\n", UDT::getlasterror().getErrorMessage());
90  }
91
92  if (UDT::ERROR == UDT::listen(serv, 1)) {
93    printf("listen error, %s\n", UDT::getlasterror().getErrorMessage());
94  }
95
96  QTimer *timer = new QTimer(this);
97  connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
98  timer->start(20);
99}
100
101Manager::~Manager() {
102  emit killUdtSockets();
103
104  // delete main_layout;
105  UDT::cleanup();
106}
107
108void Manager::acceptConnections(void) {
109  static UDTSOCKET first_socket = 0;
110  UDTSOCKET socket;
111
112  sockaddr_in their_addr;
113  int namelen = sizeof(their_addr);
114
115  if (UDT::INVALID_SOCK ==
116      (socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
117    if (UDT::getlasterror().getErrorCode() != 6002)
118      printf("accept: %s, code %i\n", UDT::getlasterror().getErrorMessage(),
119             UDT::getlasterror().getErrorCode());
120    return;
121  } else {
122    printf("connected to %s:%i\n", inet_ntoa(their_addr.sin_addr),
123           their_addr.sin_port);
124
125    if (!first_socket) {
126      first_socket = socket;
127      return;
128    } else {
129      QThread *thread = new QThread(this);
130      UdtSocket *new_udt = new UdtSocket(first_socket, socket, name);
131      new_udt->moveToThread(thread);
132
133      newConnection(new_udt);
134
135      connect(this, SIGNAL(killUdtSockets()), thread, SLOT(quit()));
136      connect(this, SIGNAL(killUdtSockets()), new_udt, SLOT(kill()),
137              Qt::BlockingQueuedConnection);
138
139      connect(thread, SIGNAL(started()), new_udt, SLOT(handleConnections()));
140
141      thread->start();
142      first_socket = 0;
143    }
144  }
145}
146
147void Manager::newConnection(UdtSocket *socket) {
148
149  // no tabs to 2 tabs
150  if (connectionsLayout.count() == 1) {
151    tabBar->addTab(hiddenTabName);
152    currentTab = 0;
153    connectionsWidget.at(0)->show();
154  }
155
156  // layout utilisateur
157  ConnectionLayout *newLayout = new ConnectionLayout(socket, "interface");
158  connectionsLayout.append(newLayout);
159  connect(newLayout, SIGNAL(setRemoteName(QString)), this,
160          SLOT(tabName(QString)));
161  connect(newLayout, SIGNAL(computedRxRate(float)), this,
162          SLOT(printRxRates(float)));
163  connect(socket, SIGNAL(dataReady(char *, int)), newLayout,
164          SLOT(receive(char *, int)));
165  connect(newLayout, SIGNAL(destroyed(QObject *)), this,
166          SLOT(layoutDestroyed(QObject *)));
167  connect(socket, SIGNAL(destroyed()), newLayout, SLOT(deleteLater()));
168
169  // widget
170  QWidget *newWidget = new QWidget();
171  connectionsWidget.append(newWidget);
172  newWidget->setLayout(newLayout->getQGridLayout());
173  managerLayout->insertWidget(1, newWidget);
174  newWidget->hide();
175
176  if (connectionsLayout.count() == 1) { // first connection
177    newWidget->show();
178  } else { // add a tab for the new connection
179    tabBar->addTab("unknown");
180  }
181}
182
183void Manager::printRxRates(float rxRate) {
184  int index = connectionsLayout.indexOf((ConnectionLayout *)sender());
185
186  if (tabBar->count() == 0) {
187    status->showMessage(tr("rx rate %1 kB/s").arg(rxRate,0,'f',3));
188  } else if (index==tabBar->currentIndex()) {
189    status->showMessage(tr("%1 rx rate %2 kB/s").arg(tabBar->tabText(index)).arg(rxRate,0,'f',3));
190  }
191}
192
193void Manager::tabBarCurrentChanged(int index) {
194  if (index >= 0) {
195    connectionsWidget.at(currentTab)->hide();
196    connectionsWidget.at(index)->show();
197    currentTab = index;
198  } else {
199    currentTab = 0;
200    connectionsWidget.at(0)->show();
201  }
202}
203
204void Manager::tabName(QString name) {
205  int index = connectionsLayout.indexOf((ConnectionLayout *)sender());
206  if (tabBar->count() == 0) {
207    hiddenTabName = name;
208  } else {
209    tabBar->setTabText(index, name);
210  }
211}
212
213void Manager::layoutDestroyed(QObject *obj) {
214  int index = connectionsLayout.indexOf((ConnectionLayout *)obj);
215
216  if (tabBar->count() > 1) {
217    tabBar->removeTab(index);
218  }
219
220  delete connectionsWidget.at(index);
221  connectionsWidget.removeAt(index);
222  connectionsLayout.removeOne((ConnectionLayout *)obj);
223
224  if (connectionsLayout.count() == 1) {
225    hiddenTabName = tabBar->tabText(0);
226    tabBar->removeTab(0);
227  }
228
229  if (connectionsLayout.count() == 0) {
230    status->showMessage("");
231  }
232}
233
234void Manager::load(void) {
235  QString dir_name =
236      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
237
238  if (dir_name != "") {
239    for (int i = 0; i < connectionsLayout.count(); i++) {
240      QFile *file;
241      file = new QFile(dir_name + "/" +
242                       connectionsLayout.at(i)->getRemoteName() + ".xml");
243      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
244        QMessageBox::warning(this, "Warning",
245                             "Enable to load " +
246                                 connectionsLayout.at(i)->getRemoteName() +
247                                 ".xml");
248        continue;
249      }
250
251      QDomDocument doc;
252      QString errorMsg;
253      int errorLine;
254      int errorColumn;
255      if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
256        QMessageBox::critical(
257            this, "Error",
258            "unable to read " + connectionsLayout.at(i)->getRemoteName() +
259                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
260                "," + QString::number(errorColumn) + ")");
261      } else {
262        connectionsLayout.at(i)->LoadXml(doc);
263      }
264      delete file;
265    }
266  }
267}
268
269void Manager::save(void) {
270  bool isUptodate = true;
271
272  for (int i = 0; i < connectionsLayout.count(); i++) {
273    if (!connectionsLayout.at(i)->IsUptodate()) {
274      isUptodate = false;
275      break;
276    }
277  }
278
279  if (!isUptodate) {
280    QMessageBox msgBox;
281    msgBox.setText("There are pending modifications");
282    msgBox.setInformativeText("Apply and save?");
283    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
284    msgBox.setDefaultButton(QMessageBox::Yes);
285    int ret = msgBox.exec();
286
287    switch (ret) {
288    case QMessageBox::Yes:
289      send();
290      break;
291    case QMessageBox::Cancel:
292      return;
293      break;
294    default:
295      // should never be reached
296      break;
297    }
298  }
299
300  // create dirctory for storage
301  QDateTime dateTime = QDateTime::currentDateTime();
302  QString dir_name =
303      "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
304  if (QDir().exists(dir_name) == true) {
305    dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
306  }
307  QDir().mkdir(dir_name);
308
309  for (int i = 0; i < connectionsLayout.count(); i++) {
310    QDomDocument *xml = new QDomDocument("remote_ui_xml");
311
312    connectionsLayout.at(i)->GetFullXml((QDomElement *)xml);
313
314    QFile fichier(dir_name + "/" + connectionsLayout.at(i)->getRemoteName() +
315                  ".xml");
316    QString write_doc = (xml->ownerDocument()).toString();
317
318    if (!fichier.open(QIODevice::WriteOnly)) {
319      fichier.close();
320      QMessageBox::critical(this, "Error", "Enable to write XML");
321      continue;
322    }
323    QTextStream stream(&fichier);
324    stream << write_doc; // On utilise l'opérateur << pour écrire write_doc dans
325                         // le document XML.
326    fichier.close();
327
328    delete xml;
329  }
330
331  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
332}
333
334void Manager::send(void) {
335  for (int i = 0; i < connectionsLayout.count(); i++) {
336    QDomDocument doc("remote_ui_xml");
337    connectionsLayout.at(i)->GetUpdateXml((QDomElement *)&doc);
338    // printf("merge\n%s\n",doc.toString().toLocal8Bit().constData());
339
340    connectionsLayout.at(i)->XmlToSend(doc);
341  }
342}
343
344void Manager::reset() {
345  for (int i = 0; i < connectionsLayout.count(); i++)
346    connectionsLayout.at(i)->ResetAllChilds();
347}
Note: See TracBrowser for help on using the repository browser.