source: flair-src/trunk/tools/FlairGCS/src/Manager.cpp @ 269

Last change on this file since 269 was 269, checked in by Sanahuja Guillaume, 3 years ago

flairgcs:
speed up processing time when receiving datas from uav
triger watchdog while receiving datas from uav
(avoids connection lost in uav)

File size: 12.0 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 "file_ui.h"
10#include <QDate>
11#include <QFileDialog>
12#include <QMessageBox>
13#include <QPushButton>
14#include <QTabBar>
15#include <QTimer>
16#include <QThread>
17#include <QTextStream>
18#include <QVBoxLayout>
19#include <QModelIndex>
20#include <QStatusBar>
21#include <qendian.h>
22#include <iostream>
23#include <string>
24#include <fstream>
25#include <stdio.h>
26
27#ifndef WIN32
28#include <arpa/inet.h>
29#else
30#include <winsock2.h>
31#include <ws2tcpip.h>
32#endif
33
34using namespace std;
35
36Manager::Manager(QString name, int port) : QWidget() {
37  qRegisterMetaType<QModelIndex>("QModelIndex"); // pour le file ui??
38  this->name = name;
39//fprintf(stderr,stderr,"Manager %x\n",thread());
40  setWindowTitle(name);
41
42  // manager layout
43  managerLayout = new QVBoxLayout;
44  setLayout(managerLayout);
45
46  // tab bar for multiple connections
47  tabBar = new QTabBar();
48  //tabBar->setTabsClosable(true);
49  managerLayout->addWidget(tabBar);
50  connect(tabBar, SIGNAL(currentChanged(int)), this,
51          SLOT(tabBarCurrentChanged(int)));
52  currentTab = 0;
53
54  // layout boutons
55  button_layout = new QGridLayout();
56  managerLayout->addLayout(button_layout);
57
58  // boutons du button_Layout
59  send_button = new QPushButton("apply all");
60  reset_button = new QPushButton("reset all");
61  load_button = new QPushButton("load all locally");
62  save_button = new QPushButton("save all locally");
63  button_layout->addWidget(send_button, 0, 0);
64  button_layout->addWidget(reset_button, 0, 1);
65  button_layout->addWidget(load_button, 0, 2);
66  button_layout->addWidget(save_button, 0, 3);
67
68  connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
69  connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
70  connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
71  connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
72
73  status=new QStatusBar();
74  status->setSizeGripEnabled(false);
75  button_layout->addWidget(status, 1,0);
76
77  UDT::startup();
78  serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
79
80  // for non blocking accept
81  bool blocking = false;
82  UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
83//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
84  sockaddr_in my_addr;
85  my_addr.sin_family = AF_INET;
86  my_addr.sin_port = htons(port);
87  my_addr.sin_addr.s_addr = INADDR_ANY;
88  memset(&(my_addr.sin_zero), '\0', 8);
89
90  if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
91    fprintf(stderr,"bind error, %s\n", UDT::getlasterror().getErrorMessage());
92  }
93
94  if (UDT::ERROR == UDT::listen(serv, 1)) {
95    fprintf(stderr,"listen error, %s\n", UDT::getlasterror().getErrorMessage());
96  }
97
98 
99  icon_green = QIcon(":green.png");
100  icon_red = QIcon(":red.png");
101  icon_orange = QIcon(":orange.png");
102 
103 
104  QTimer *timer = new QTimer(this);
105  connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
106  timer->start(500);
107}
108
109Manager::~Manager() {
110  for (int i = 0; i < connections.count(); i++) {
111    if(connections.at(i).socket!=NULL) {
112      connections.at(i).socket->kill();
113      connections.at(i).socket->thread()->wait();
114    }
115  }
116
117  // delete main_layout;
118  UDT::cleanup();
119}
120
121void Manager::acceptConnections(void) {
122  UDTSOCKET socket;
123
124  sockaddr_in their_addr;
125  int namelen = sizeof(their_addr);
126
127  if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
128    if (UDT::getlasterror().getErrorCode() != 6002)
129      fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
130    return;
131  } else {
132    QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
133    fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
134   
135    QThread *thread = new QThread(this);
136    UdtSocket *udtSocket = new UdtSocket(socket,name);
137    udtSocket->moveToThread(thread);
138   
139    connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
140    connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
141    connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
142
143    thread->start(); 
144  }
145}
146
147void Manager::newConnectionLayout(QString name) {
148  UdtSocket* udtSocket=(UdtSocket *)sender();
149 
150  ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
151  connect(udtSocket, SIGNAL(UDTStats(QString,bool)), newLayout, SIGNAL(UDTStats(QString,bool)));//connection in 2 steps to get udtsocket as sender
152  connect(newLayout, SIGNAL(UDTStats(QString,bool)), this, SLOT(printUDTStats(QString,bool)));
153  connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
154  connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
155  connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
156  connect(udtSocket, SIGNAL(destroyed(QObject *)), newLayout, SLOT(udtSocketDestroyed(QObject *)));
157 
158  // widget
159  QWidget *newWidget = new QWidget();
160  newWidget->setLayout(newLayout->getQGridLayout());
161  managerLayout->insertWidget(1, newWidget);
162  newWidget->hide();
163 
164  connections_t connection;
165  connection.layout=newLayout;
166  connection.widget=newWidget;
167  connection.socket=udtSocket;
168  connections.append(connection);
169 
170  //tab: avoid having only 1 tab (0, 2 or more)
171  if (connections.count() == 1) { // first connection
172    newWidget->show();
173    hiddenTabName = name;
174  }
175  if (connections.count() == 2) {
176    if(connections[0].socket!=NULL) {
177      tabBar->addTab(icon_green,hiddenTabName);
178    } else {
179      tabBar->addTab(icon_red,hiddenTabName);
180    }
181    currentTab = 0;
182  }
183  if (connections.count() > 1) {
184    tabBar->addTab(icon_green,name);
185  }
186}
187
188void Manager::udtSocketDestroyed(QObject *obj) {
189  //mark socket as not valid, it can be a connection lost
190  //in this case we keep the layout for reading, and mark it as problematic (socket=NULL)
191  for(int i=0;i<connections.count();i++) {
192    if(connections.at(i).socket==(UdtSocket *)obj) {
193      connections[i].socket=NULL;
194      tabBar->setTabIcon(i,icon_red);
195      break;
196    }
197  }
198}
199
200void Manager::layoutDestroyed(QObject *obj) {
201  //remove the connection, it comes from a proper close
202  int index=-1;
203  for(int i=0;i<connections.count();i++) {
204    if(connections.at(i).layout==(ConnectionLayout *)obj) {
205      delete connections.at(i).widget;
206      //connections[i].widget=NULL;
207      //connections[i].layout=NULL;
208      connections.removeAt(i);
209      index=i;
210      break;
211    }
212  }
213 
214  if(index==-1) {
215    fprintf(stderr,"layoutDestroyed: error, layout not found!\n");
216    return;
217  }
218 
219  //tab: avoid having only 1 tab (only 0, 2 or more)
220  if (tabBar->count() > 1) {
221    tabBar->removeTab(index);
222  }
223
224  if (connections.count() == 1) {
225    hiddenTabName = tabBar->tabText(0);
226    tabBar->removeTab(0);
227  }
228
229  if (connections.count() == 0) {
230    status->showMessage("");
231  }
232}
233
234void Manager::newFileUI(UDTSOCKET socket) {
235  QThread *thread = new QThread(this);
236  file_ui* fileUi = new file_ui(socket,name);
237  fileUi->moveToThread(thread);
238  connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
239  connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
240  thread->start();
241}
242
243void Manager::deleteFileUI(void) {
244  sender()->thread()->quit();
245  delete sender();
246}
247
248void Manager::printUDTStats(QString stats,bool loosingPackets) {
249  int index = -1;
250  for(int i=0;i<connections.count();i++) {
251    if(connections.at(i).layout==(ConnectionLayout *)sender()) {
252      index=i;
253      break;
254    }
255  }
256 
257  if(index==-1) return;
258 
259  if(!loosingPackets) {
260    tabBar->setTabIcon(index,icon_green);
261  } else {
262    tabBar->setTabIcon(index,icon_orange);
263  }
264 
265  if (tabBar->count() == 0) {
266    status->showMessage(stats);
267  } else if (index==tabBar->currentIndex()) {
268    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
269  }
270}
271
272void Manager::tabBarCurrentChanged(int index) {
273 
274  if (index >= 0) {
275    //if we are coming from layout destroyed
276    if(currentTab<connections.count()) connections.at(currentTab).widget->hide();
277    connections.at(index).widget->show();
278    currentTab = index;
279  } else {
280    currentTab = 0;
281    connections.at(0).widget->show();
282  }
283  QString msg="not connected";
284  if (tabBar->count() == 0) {
285    if(connections.at(0).socket!=NULL) msg=connections.at(0).socket->getUDTStats();
286   
287  } else {
288    if(connections.at(index).socket!=NULL) msg=QString("%1: %2").arg(tabBar->tabText(index)).arg(connections.at(index).socket->getUDTStats());
289  }
290  status->showMessage(msg);
291}
292
293void Manager::load(void) {
294  QString dir_name =
295      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
296
297  if (dir_name != "") {
298    for (int i = 0; i < connections.count(); i++) {
299      QFile *file;
300      file = new QFile(dir_name + "/" +
301                       connections.at(i).layout->getName() + ".xml");
302      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
303        QMessageBox::warning(this, "Warning",
304                             "Enable to load " +
305                                 connections.at(i).layout->getName() +
306                                 ".xml");
307        continue;
308      }
309
310      QDomDocument doc;
311      QString errorMsg;
312      int errorLine;
313      int errorColumn;
314      if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
315        QMessageBox::critical(
316            this, "Error",
317            "unable to read " + connections.at(i).layout->getName() +
318                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
319                "," + QString::number(errorColumn) + ")");
320      } else {
321        connections.at(i).layout->LoadXml(&doc);
322      }
323      delete file;
324    }
325  }
326}
327
328void Manager::save(void) {
329  bool isUptodate = true;
330
331  for (int i = 0; i < connections.count(); i++) {
332    if (!connections.at(i).layout->IsUptodate()) {
333      isUptodate = false;
334      break;
335    }
336  }
337
338  if (!isUptodate) {
339    QMessageBox msgBox;
340    msgBox.setText("There are pending modifications");
341    msgBox.setInformativeText("Apply and save?");
342    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
343    msgBox.setDefaultButton(QMessageBox::Yes);
344    int ret = msgBox.exec();
345
346    switch (ret) {
347    case QMessageBox::Yes:
348      send();
349      break;
350    case QMessageBox::Cancel:
351      return;
352      break;
353    default:
354      // should never be reached
355      break;
356    }
357  }
358
359  // create dirctory for storage
360  QDateTime dateTime = QDateTime::currentDateTime();
361  QString dir_name =
362      "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
363  if (QDir().exists(dir_name) == true) {
364    dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
365  }
366  QDir().mkdir(dir_name);
367
368  for (int i = 0; i < connections.count(); i++) {
369    QDomDocument *xml = new QDomDocument("remote_ui_xml");
370
371    connections.at(i).layout->GetFullXml((QDomElement *)xml);
372
373    QFile fichier(dir_name + "/" + connections.at(i).layout->getName() +
374                  ".xml");
375    QString write_doc = (xml->ownerDocument()).toString();
376
377    if (!fichier.open(QIODevice::WriteOnly)) {
378      fichier.close();
379      QMessageBox::critical(this, "Error", "Enable to write XML");
380      continue;
381    }
382    QTextStream stream(&fichier);
383    stream << write_doc;
384    fichier.close();
385
386    delete xml;
387  }
388
389  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
390}
391
392void Manager::send(void) {
393  for (int i = 0; i < connections.count(); i++) {
394    if(connections.at(i).socket!=NULL) {
395      QDomDocument doc("remote_ui_xml");
396      connections.at(i).layout->GetUpdateXml((QDomElement *)&doc);
397      // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
398
399      connections.at(i).layout->XmlToSend(doc);
400    }
401  }
402}
403
404void Manager::reset() {
405  for (int i = 0; i < connections.count(); i++)
406    connections.at(i).layout->ResetAllChilds();
407}
Note: See TracBrowser for help on using the repository browser.