udp_server.cpp
Go to the documentation of this file.
1 /*Wensocket PlotJuggler Plugin license(Faircode, Davide Faconti)
2 
3 Copyright(C) 2018 Philippe Gauthier - ISIR - UPMC
4 Copyright(C) 2020 Davide Faconti
5 Permission is hereby granted to any person obtaining a copy of this software and
6 associated documentation files(the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and / or sell copies("Use") of the Software, and to permit persons
9 to whom the Software is furnished to do so. The above copyright notice and this permission
10 notice shall be included in all copies or substantial portions of the Software. THE
11 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
12 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
14 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 THE SOFTWARE.
17 */
18 #include "udp_server.h"
19 #include <QTextStream>
20 #include <QFile>
21 #include <QMessageBox>
22 #include <QDebug>
23 #include <QSettings>
24 #include <QDialog>
25 #include <mutex>
26 #include <QWebSocket>
27 #include <QIntValidator>
28 #include <QMessageBox>
29 #include <chrono>
30 #include <QNetworkDatagram>
31 #include <QNetworkInterface>
32 
33 #include "ui_udp_server.h"
34 
35 class UdpServerDialog : public QDialog
36 {
37 public:
38  UdpServerDialog() : QDialog(nullptr), ui(new Ui::UDPServerDialog)
39  {
40  ui->setupUi(this);
41  ui->lineEditPort->setValidator(new QIntValidator());
42  setWindowTitle("UDP Server");
43 
44  connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
45  connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
46  }
48  {
49  while (ui->layoutOptions->count() > 0)
50  {
51  auto item = ui->layoutOptions->takeAt(0);
52  item->widget()->setParent(nullptr);
53  }
54  delete ui;
55  }
56  Ui::UDPServerDialog* ui;
57 };
58 
59 UDP_Server::UDP_Server() : _running(false)
60 {
61 }
62 
64 {
65  shutdown();
66 }
67 
68 bool UDP_Server::start(QStringList*)
69 {
70  if (_running)
71  {
72  return _running;
73  }
74 
75  if (parserFactories() == nullptr || parserFactories()->empty())
76  {
77  QMessageBox::warning(nullptr, tr("UDP Server"), tr("No available MessageParsers"),
78  QMessageBox::Ok);
79  _running = false;
80  return false;
81  }
82 
83  bool ok = false;
84 
85  UdpServerDialog dialog;
86 
87  for (const auto& it : *parserFactories())
88  {
89  dialog.ui->comboBoxProtocol->addItem(it.first);
90 
91  if (auto widget = it.second->optionsWidget())
92  {
93  widget->setVisible(false);
94  dialog.ui->layoutOptions->addWidget(widget);
95  }
96  }
97 
98  // load previous values
99  QSettings settings;
100  QString protocol = settings.value("UDP_Server::protocol", "JSON").toString();
101  QString address_str = settings.value("UDP_Server::address", "127.0.0.1").toString();
102  int port = settings.value("UDP_Server::port", 9870).toInt();
103 
104  dialog.ui->lineEditAddress->setText(address_str);
105  dialog.ui->lineEditPort->setText(QString::number(port));
106 
107  ParserFactoryPlugin::Ptr parser_creator;
108 
109  auto onComboChanged = [&](const QString& selected_protocol) {
110  if (parser_creator)
111  {
112  if (auto prev_widget = parser_creator->optionsWidget())
113  {
114  prev_widget->setVisible(false);
115  }
116  }
117  parser_creator = parserFactories()->at(selected_protocol);
118 
119  if (auto widget = parser_creator->optionsWidget())
120  {
121  widget->setVisible(true);
122  }
123  };
124 
125  connect(dialog.ui->comboBoxProtocol,
126  qOverload<const QString&>(&QComboBox::currentIndexChanged), this,
127  onComboChanged);
128 
129  dialog.ui->comboBoxProtocol->setCurrentText(protocol);
130  onComboChanged(protocol);
131 
132  int res = dialog.exec();
133  if (res == QDialog::Rejected)
134  {
135  _running = false;
136  return false;
137  }
138 
139  address_str = dialog.ui->lineEditAddress->text();
140  port = dialog.ui->lineEditPort->text().toUShort(&ok);
141  protocol = dialog.ui->comboBoxProtocol->currentText();
142 
143  _parser = parser_creator->createParser({}, {}, {}, dataMap());
144 
145  // save back to service
146  settings.setValue("UDP_Server::protocol", protocol);
147  settings.setValue("UDP_Server::address", address_str);
148  settings.setValue("UDP_Server::port", port);
149 
150  QHostAddress address(address_str);
151 
152  bool success = true;
153  success &= !address.isNull();
154 
155  _udp_socket = new QUdpSocket();
156 
157  if (!address.isMulticast())
158  {
159  success &= _udp_socket->bind(address, port);
160  }
161  else
162  {
163  success &= _udp_socket->bind(
164  address, port, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint);
165 
166  // Add multicast group membership to all interfaces which support multicast.
167  for (const auto& interface : QNetworkInterface::allInterfaces())
168  {
169  QNetworkInterface::InterfaceFlags iflags = interface.flags();
170  if (interface.isValid() && !iflags.testFlag(QNetworkInterface::IsLoopBack) &&
171  iflags.testFlag(QNetworkInterface::CanMulticast) &&
172  iflags.testFlag(QNetworkInterface::IsRunning))
173  {
174  success &= _udp_socket->joinMulticastGroup(address, interface);
175  }
176  }
177  }
178 
179  _running = true;
180 
181  connect(_udp_socket, &QUdpSocket::readyRead, this, &UDP_Server::processMessage);
182 
183  if (success)
184  {
185  qDebug() << tr("UDP listening on (%1, %2)").arg(address_str).arg(port);
186  }
187  else
188  {
189  QMessageBox::warning(nullptr, tr("UDP Server"),
190  tr("Couldn't bind to UDP (%1, %2)").arg(address_str).arg(port),
191  QMessageBox::Ok);
192  shutdown();
193  }
194 
195  return _running;
196 }
197 
199 {
200  if (_running && _udp_socket)
201  {
202  _udp_socket->deleteLater();
203  _running = false;
204  }
205 }
206 
208 {
209  while (_udp_socket->hasPendingDatagrams())
210  {
211  QNetworkDatagram datagram = _udp_socket->receiveDatagram();
212 
213  using namespace std::chrono;
214  auto ts = high_resolution_clock::now().time_since_epoch();
215  double timestamp = 1e-6 * double(duration_cast<microseconds>(ts).count());
216 
217  QByteArray m = datagram.data();
218  MessageRef msg(reinterpret_cast<uint8_t*>(m.data()), m.count());
219 
220  try
221  {
222  std::lock_guard<std::mutex> lock(mutex());
223  // important use the mutex to protect any access to the data
224  _parser->parseMessage(msg, timestamp);
225  }
226  catch (std::exception& err)
227  {
228  QMessageBox::warning(nullptr, tr("UDP Server"),
229  tr("Problem parsing the message. UDP Server will be "
230  "stopped.\n%1")
231  .arg(err.what()),
232  QMessageBox::Ok);
233  shutdown();
234  // notify the GUI
235  emit closed();
236  return;
237  }
238  }
239  // notify the GUI
240  emit dataReceived();
241  return;
242 }
arg
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1875
udp_server.h
UdpServerDialog::~UdpServerDialog
~UdpServerDialog()
Definition: udp_server.cpp:47
mqtt_test_proto.msg
msg
Definition: mqtt_test_proto.py:43
UDP_Server::shutdown
virtual void shutdown() override
shutdown Stop streaming
Definition: udp_server.cpp:198
ok
ROSCPP_DECL bool ok()
UDP_Server::_running
bool _running
Definition: udp_server.h:58
detail::count
constexpr auto count() -> size_t
Definition: core.h:1222
Ui
Definition: cheatsheet_dialog.h:6
PJ::DataStreamer::parserFactories
const ParserFactories * parserFactories() const
Definition: datastreamer_base.cpp:34
PJ::DataStreamer::dataMap
PlotDataMapRef & dataMap()
Definition: datastreamer_base.h:69
PJ::DataStreamer::closed
void closed()
PJ::ParserFactoryPlugin::Ptr
std::shared_ptr< ParserFactoryPlugin > Ptr
Definition: messageparser_base.h:142
UDP_Server::UDP_Server
UDP_Server()
Definition: udp_server.cpp:59
UDP_Server::_udp_socket
QUdpSocket * _udp_socket
Definition: udp_server.h:59
UdpServerDialog::ui
Ui::UDPServerDialog * ui
Definition: udp_server.cpp:56
PJ::DataStreamer::dataReceived
void dataReceived()
PJ::MessageRef
Definition: messageparser_base.h:28
UDP_Server::_parser
PJ::MessageParserPtr _parser
Definition: udp_server.h:60
UDP_Server::start
virtual bool start(QStringList *) override
start streaming.
Definition: udp_server.cpp:68
UdpServerDialog
Definition: udp_server.cpp:35
UdpServerDialog::UdpServerDialog
UdpServerDialog()
Definition: udp_server.cpp:38
UDP_Server::processMessage
void processMessage()
Definition: udp_server.cpp:207
PJ::DataStreamer::mutex
std::mutex & mutex()
Definition: datastreamer_base.h:62
UDP_Server::~UDP_Server
virtual ~UDP_Server() override
Definition: udp_server.cpp:63
nullptr
#define nullptr
Definition: backward.hpp:386


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Aug 11 2024 02:24:26