summaryrefslogtreecommitdiffstats
path: root/examples/protobuf/sensors/emulator
diff options
context:
space:
mode:
authorAlexey Edelev <alexey.edelev@qt.io>2023-01-06 18:18:36 +0100
committerAlexey Edelev <alexey.edelev@qt.io>2023-02-13 15:10:52 +0100
commit76d94d29eac9b359cadd4e899a239a727c91d42f (patch)
tree65d0f6328d33da7689f1d85d694e9100fc4e4f04 /examples/protobuf/sensors/emulator
parent1a72cce91d0bcd4e13c5347892abb177f12f971a (diff)
Add example of communication using protobuf messages
Add the protobuf example that emulates the work of dummy sensors that send data to the sensor client. The example uses UDP sockets to send datagrams that contain protobuf messages. Messages consist of two layers: - The Type-Length-Value wrapping message that specifies the the message type and allows to verify the message size. - Sensor message that contains a sensor data. The example intends to show how to generate the code from the protobuf schema and use it in simple UDP signalling protocol on both sender and receiver sides. Both client and emulator have simple UI implemented using QtWidgets. Task-number: QTBUG-109598 Pick-to: 6.5 Change-Id: I13e2c5bcd995b8aa6d873c495a7bd83f6651a061 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'examples/protobuf/sensors/emulator')
-rw-r--r--examples/protobuf/sensors/emulator/CMakeLists.txt25
-rw-r--r--examples/protobuf/sensors/emulator/emulatorconsole.cpp58
-rw-r--r--examples/protobuf/sensors/emulator/emulatorconsole.h37
-rw-r--r--examples/protobuf/sensors/emulator/emulatorconsole.ui326
-rw-r--r--examples/protobuf/sensors/emulator/main.cpp21
-rw-r--r--examples/protobuf/sensors/emulator/sensoremulator.cpp52
-rw-r--r--examples/protobuf/sensors/emulator/sensoremulator.h33
7 files changed, 552 insertions, 0 deletions
diff --git a/examples/protobuf/sensors/emulator/CMakeLists.txt b/examples/protobuf/sensors/emulator/CMakeLists.txt
new file mode 100644
index 0000000..e2b23f9
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+qt_add_executable(protobuf_sensor_emulator
+ main.cpp
+ sensoremulator.h sensoremulator.cpp
+ emulatorconsole.h emulatorconsole.cpp
+ emulatorconsole.ui
+)
+
+target_link_libraries(protobuf_sensor_emulator PRIVATE
+ Qt6::Core
+ Qt6::Protobuf
+ Qt6::Widgets
+ Qt6::Network
+ protobuf_sensors
+)
+
+install(TARGETS protobuf_sensor_emulator
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/protobuf/sensors/emulator/emulatorconsole.cpp b/examples/protobuf/sensors/emulator/emulatorconsole.cpp
new file mode 100644
index 0000000..99eb87f
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/emulatorconsole.cpp
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "emulatorconsole.h"
+#include "ui_emulatorconsole.h"
+
+#include <QDoubleValidator>
+#include <QIntValidator>
+
+#include "sensors.qpb.h"
+
+EmulatorConsole::EmulatorConsole(QWidget *parent) : QWidget(parent), ui(new Ui::EmulatorConsole)
+{
+ ui->setupUi(this);
+ auto validator = new QDoubleValidator(-90, 90, 7, ui->latitudeValue);
+ validator->setLocale(QLocale::c());
+ ui->latitudeValue->setValidator(validator);
+
+ validator = new QDoubleValidator(-180, 180, 7, ui->longitudeValue);
+ validator->setLocale(QLocale::c());
+ ui->longitudeValue->setValidator(validator);
+
+ validator = new QDoubleValidator(-1000, 1000, 7, ui->altitudeValue);
+ validator->setLocale(QLocale::c());
+ ui->altitudeValue->setValidator(validator);
+ ui->temperatureValue->setValidator(new QIntValidator(-50, 50, ui->temperatureValue));
+// ![0]
+ QObject::connect(ui->sendCoordinates, &QPushButton::clicked, this, [this]() {
+ qt::examples::sensors::Coordinates coord;
+ coord.setLatitude(ui->latitudeValue->text().toDouble());
+ coord.setLongitude(ui->longitudeValue->text().toDouble());
+ coord.setAltitude(ui->altitudeValue->text().toDouble());
+ emit coordinatesUpdated(coord);
+ });
+// ![0]
+
+ QObject::connect(ui->sendTemperature, &QPushButton::clicked, this, [this]() {
+ qt::examples::sensors::Temperature temp;
+ temp.setValue(ui->temperatureValue->text().toInt());
+ temp.setUnits(ui->celciusRadio->isChecked()
+ ? qt::examples::sensors::Temperature::Celsius
+ : qt::examples::sensors::Temperature::Farenheit);
+ emit temperatureUpdated(temp);
+ });
+
+ QObject::connect(ui->sendMessage, &QPushButton::clicked, this, [this]() {
+ qt::examples::sensors::WarningNotification warn;
+ warn.setText(ui->warningText->toPlainText());
+ emit warning(warn);
+ });
+}
+
+EmulatorConsole::~EmulatorConsole()
+{
+ delete ui;
+}
+
+#include "moc_emulatorconsole.cpp"
diff --git a/examples/protobuf/sensors/emulator/emulatorconsole.h b/examples/protobuf/sensors/emulator/emulatorconsole.h
new file mode 100644
index 0000000..7a499e0
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/emulatorconsole.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef EMULATORCONSOLE_H
+#define EMULATORCONSOLE_H
+
+#include <QWidget>
+
+namespace qt::examples::sensors {
+class Coordinates;
+class Temperature;
+class WarningNotification;
+} // namespace qt::examples::sensors
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class EmulatorConsole;
+}
+QT_END_NAMESPACE
+
+class EmulatorConsole : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit EmulatorConsole(QWidget *parent = nullptr);
+ ~EmulatorConsole();
+
+signals:
+ void coordinatesUpdated(const qt::examples::sensors::Coordinates &);
+ void temperatureUpdated(const qt::examples::sensors::Temperature &);
+ void warning(const qt::examples::sensors::WarningNotification &);
+
+private:
+ Ui::EmulatorConsole *ui;
+};
+#endif // EMULATORCONSOLE_H
diff --git a/examples/protobuf/sensors/emulator/emulatorconsole.ui b/examples/protobuf/sensors/emulator/emulatorconsole.ui
new file mode 100644
index 0000000..5b2a262
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/emulatorconsole.ui
@@ -0,0 +1,326 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EmulatorConsole</class>
+ <widget class="QWidget" name="EmulatorConsole">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>333</width>
+ <height>456</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Emulator Console</string>
+ </property>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>241</width>
+ <height>141</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Coordinates</string>
+ </property>
+ <widget class="QWidget" name="layoutWidget1">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>70</y>
+ <width>216</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Longitude</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="longitudeValue">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>13.5331485</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget2">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>100</y>
+ <width>216</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Altitude</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="altitudeValue">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>0.0</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>40</y>
+ <width>216</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Latitude</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="latitudeValue">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>52.4317463</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>160</y>
+ <width>241</width>
+ <height>141</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Weather</string>
+ </property>
+ <widget class="QWidget" name="layoutWidget4">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>40</y>
+ <width>216</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Temperature</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="temperatureValue">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>20</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QRadioButton" name="celciusRadio">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>80</y>
+ <width>112</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Celcius</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" name="fahrenheitRadio">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>110</y>
+ <width>112</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Fahrenheit</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>310</y>
+ <width>241</width>
+ <height>141</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Warning message</string>
+ </property>
+ <widget class="QTextEdit" name="warningText">
+ <property name="geometry">
+ <rect>
+ <x>3</x>
+ <y>24</y>
+ <width>231</width>
+ <height>111</height>
+ </rect>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+hr { height: 1px; border-width: 0; }
+li.unchecked::marker { content: &quot;\2610&quot;; }
+li.checked::marker { content: &quot;\2612&quot;; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;!!!A simple warning message!!!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QPushButton" name="sendCoordinates">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>120</y>
+ <width>61</width>
+ <height>26</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Send</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="sendTemperature">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>270</y>
+ <width>61</width>
+ <height>26</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Send</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="sendMessage">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>420</y>
+ <width>61</width>
+ <height>26</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Send</string>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/protobuf/sensors/emulator/main.cpp b/examples/protobuf/sensors/emulator/main.cpp
new file mode 100644
index 0000000..a4448b8
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/main.cpp
@@ -0,0 +1,21 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "emulatorconsole.h"
+
+#include <QApplication>
+#include "sensoremulator.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ SensorEmulator emul;
+ EmulatorConsole console;
+ QObject::connect(&console, &EmulatorConsole::coordinatesUpdated, &emul,
+ &SensorEmulator::sendCoordinates);
+ QObject::connect(&console, &EmulatorConsole::temperatureUpdated, &emul,
+ &SensorEmulator::sendTemperature);
+ QObject::connect(&console, &EmulatorConsole::warning, &emul, &SensorEmulator::sendWarning);
+ console.show();
+ return app.exec();
+}
diff --git a/examples/protobuf/sensors/emulator/sensoremulator.cpp b/examples/protobuf/sensors/emulator/sensoremulator.cpp
new file mode 100644
index 0000000..eee4340
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/sensoremulator.cpp
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "sensoremulator.h"
+
+#include <QDebug>
+#include <QNetworkDatagram>
+
+#include "tlv.qpb.h"
+#include "sensors.qpb.h"
+
+namespace {
+QByteArray makeTlvMessage(QProtobufSerializer *serializer, const QByteArray &data,
+ qt::examples::sensors::tlv::MessageTypeGadget::MessageType type)
+{
+//! [0]
+ Q_ASSERT(serializer != nullptr);
+ qt::examples::sensors::tlv::TlvMessage msg;
+ msg.setType(type);
+ msg.setValue(data);
+ return msg.serialize(serializer);
+//! [0]
+}
+} // namespace
+
+SensorEmulator::SensorEmulator(QObject *parent) : QObject(parent) { }
+
+void SensorEmulator::send(const QByteArray &data)
+{
+ if (m_socket.writeDatagram(data, QHostAddress::LocalHost, 65500) == -1)
+ qWarning() << "Unable to send data of size: " << data.size() << "to UDP port 65500";
+}
+
+void SensorEmulator::sendCoordinates(const qt::examples::sensors::Coordinates &coords)
+{
+ send(makeTlvMessage(&m_serializer, coords.serialize(&m_serializer),
+ qt::examples::sensors::tlv::MessageTypeGadget::Coordinates));
+}
+
+void SensorEmulator::sendTemperature(const qt::examples::sensors::Temperature &temp)
+{
+ send(makeTlvMessage(&m_serializer, temp.serialize(&m_serializer),
+ qt::examples::sensors::tlv::MessageTypeGadget::Temperature));
+}
+
+void SensorEmulator::sendWarning(const qt::examples::sensors::WarningNotification &warn)
+{
+ send(makeTlvMessage(&m_serializer, warn.serialize(&m_serializer),
+ qt::examples::sensors::tlv::MessageTypeGadget::WarningNotification));
+}
+
+#include "moc_sensoremulator.cpp"
diff --git a/examples/protobuf/sensors/emulator/sensoremulator.h b/examples/protobuf/sensors/emulator/sensoremulator.h
new file mode 100644
index 0000000..e8d041a
--- /dev/null
+++ b/examples/protobuf/sensors/emulator/sensoremulator.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SENSOREMULATOR_H
+#define SENSOREMULATOR_H
+
+#include <QObject>
+#include <QUdpSocket>
+#include <QProtobufSerializer>
+
+namespace qt::examples::sensors {
+class Coordinates;
+class Temperature;
+class WarningNotification;
+} // namespace qt::examples::sensors
+class SensorEmulator : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SensorEmulator(QObject *parent = nullptr);
+
+ void sendCoordinates(const qt::examples::sensors::Coordinates &coords);
+ void sendTemperature(const qt::examples::sensors::Temperature &temp);
+ void sendWarning(const qt::examples::sensors::WarningNotification &warn);
+
+private:
+ void send(const QByteArray &data);
+
+ QUdpSocket m_socket;
+ QProtobufSerializer m_serializer;
+};
+
+#endif // SENSOREMULATOR_H