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 address_str = settings.value("UDP_Server::address", "127.0.0.1").toString();
101  int port = settings.value("UDP_Server::port", 9870).toInt();
102  QString protocol = settings.value("UDP_Server::protocol").toString();
103  if (parserFactories()->find(protocol) == parserFactories()->end())
104  {
105  protocol = "json";
106  }
107 
108  dialog.ui->lineEditAddress->setText(address_str);
109  dialog.ui->lineEditPort->setText(QString::number(port));
110 
111  ParserFactoryPlugin::Ptr parser_creator;
112 
113  auto onComboChanged = [&](const QString& selected_protocol) {
114  if (parser_creator)
115  {
116  if (auto prev_widget = parser_creator->optionsWidget())
117  {
118  prev_widget->setVisible(false);
119  }
120  }
121  parser_creator = parserFactories()->at(selected_protocol);
122 
123  if (auto widget = parser_creator->optionsWidget())
124  {
125  widget->setVisible(true);
126  }
127  };
128 
129  connect(dialog.ui->comboBoxProtocol,
130  qOverload<const QString&>(&QComboBox::currentIndexChanged), this,
131  onComboChanged);
132 
133  dialog.ui->comboBoxProtocol->setCurrentText(protocol);
134  onComboChanged(protocol);
135 
136  int res = dialog.exec();
137  if (res == QDialog::Rejected)
138  {
139  _running = false;
140  return false;
141  }
142 
143  address_str = dialog.ui->lineEditAddress->text();
144  port = dialog.ui->lineEditPort->text().toUShort(&ok);
145  protocol = dialog.ui->comboBoxProtocol->currentText();
146 
147  _parser = parser_creator->createParser({}, {}, {}, dataMap());
148 
149  // save back to service
150  settings.setValue("UDP_Server::protocol", protocol);
151  settings.setValue("UDP_Server::address", address_str);
152  settings.setValue("UDP_Server::port", port);
153 
154  QHostAddress address(address_str);
155 
156  bool success = true;
157  success &= !address.isNull();
158 
159  _udp_socket = new QUdpSocket();
160 
161  if (!address.isMulticast())
162  {
163  success &= _udp_socket->bind(address, port);
164  }
165  else
166  {
167  success &= _udp_socket->bind(
168  address, port, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint);
169 
170  // Add multicast group membership to all interfaces which support multicast.
171  for (const auto& interface : QNetworkInterface::allInterfaces())
172  {
173  QNetworkInterface::InterfaceFlags iflags = interface.flags();
174  if (interface.isValid() && !iflags.testFlag(QNetworkInterface::IsLoopBack) &&
175  iflags.testFlag(QNetworkInterface::CanMulticast) &&
176  iflags.testFlag(QNetworkInterface::IsRunning))
177  {
178  success &= _udp_socket->joinMulticastGroup(address, interface);
179  }
180  }
181  }
182 
183  _running = true;
184 
185  connect(_udp_socket, &QUdpSocket::readyRead, this, &UDP_Server::processMessage);
186 
187  if (success)
188  {
189  qDebug() << tr("UDP listening on (%1, %2)").arg(address_str).arg(port);
190  }
191  else
192  {
193  QMessageBox::warning(nullptr, tr("UDP Server"),
194  tr("Couldn't bind to UDP (%1, %2)").arg(address_str).arg(port),
195  QMessageBox::Ok);
196  shutdown();
197  }
198 
199  return _running;
200 }
201 
203 {
204  if (_running && _udp_socket)
205  {
206  _udp_socket->deleteLater();
207  _running = false;
208  }
209 }
210 
212 {
213  while (_udp_socket->hasPendingDatagrams())
214  {
215  QNetworkDatagram datagram = _udp_socket->receiveDatagram();
216 
217  using namespace std::chrono;
218  auto ts = high_resolution_clock::now().time_since_epoch();
219  double timestamp = 1e-6 * double(duration_cast<microseconds>(ts).count());
220 
221  QByteArray m = datagram.data();
222  MessageRef msg(reinterpret_cast<uint8_t*>(m.data()), m.count());
223 
224  try
225  {
226  std::lock_guard<std::mutex> lock(mutex());
227  // important use the mutex to protect any access to the data
228  _parser->parseMessage(msg, timestamp);
229  }
230  catch (std::exception& err)
231  {
232  QMessageBox::warning(nullptr, tr("UDP Server"),
233  tr("Problem parsing the message. UDP Server will be "
234  "stopped.\n%1")
235  .arg(err.what()),
236  QMessageBox::Ok);
237  shutdown();
238  // notify the GUI
239  emit closed();
240  return;
241  }
242  }
243  // notify the GUI
244  emit dataReceived();
245  return;
246 }
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:202
detail::find
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2154
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:211
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 Mon Nov 11 2024 03:23:48