Enroute Flight Navigation
A navigation app for VFR pilots
TrafficDataSource_Tcp.h
1/***************************************************************************
2 * Copyright (C) 2021-2024 by Stefan Kebekus *
3 * stefan.kebekus@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#pragma once
22
23#include <QPointer>
24#include <QTcpSocket>
25
26#include "traffic/TrafficDataSource_AbstractSocket.h"
27
28using namespace Qt::Literals::StringLiterals;
29
30
31namespace Traffic {
32
43
45 Q_OBJECT
46
47public:
58 TrafficDataSource_Tcp(bool isCanonical, QString hostName, quint16 port, QObject *parent = nullptr);
59
60 // Standard destructor
61 ~TrafficDataSource_Tcp() override;
62
63
64
65 //
66 // Properties
67 //
68
71 Q_PROPERTY(QString host READ host CONSTANT)
72
73
75 Q_PROPERTY(quint16 port READ port CONSTANT)
76
77
78
79 //
80 // Getter Methods
81 //
82
87 [[nodiscard]] QString dataFormat() const override { return u"FLARM/NMEA"_s; }
88
93 [[nodiscard]] QString host() const
94 {
95 return m_hostName;
96 }
97
105 [[nodiscard]] QString icon() const override { return u"/icons/material/ic_wifi.svg"_s; }
106
114 [[nodiscard]] auto sourceName() const -> QString override
115 {
116 return tr("TCP connection to %1 port %2").arg(m_hostName).arg(m_port);
117 }
118
123 [[nodiscard]] quint16 port() const
124 {
125 return m_port;
126 }
127
128public slots:
135
142
148 void setPassword(const QString& SSID, const QString& password) override;
149
150private slots:
151 // Read lines from the socket's text stream and passes the string on to
152 // processFLARMData.
153 void onReadyRead();
154
155 // This method does the actual job of sending the password to the traffic
156 // data receiver
157 //
158 // It checks if the instance is actually waiting for a password and returns
159 // if it is not.
160 //
161 // It connects the slots updatePasswordStatusOnHeartbeatChange that will
162 // respond to heartbeat (=password accepted) and
163 // updatePasswordStatusOnDisconnected (=password rejected). It will send the
164 // password and set passwordRequest_Status to "waitingForDevice"
165 void sendPassword_internal();
166
167 // This method set passwordRequest_Status to "idle", resets
168 // passwordRequest_SSID and passwordRequest_password, and disconnects the
169 // slots updatePasswordStatusOnHeartbeatChange and
170 // updatePasswordStatusOnDisconnected);
171 void resetPasswordLifecycle();
172
173 // This slot is called when the password has been rejected by the traffic
174 // data receiver. It clears the password from the database, schedules a
175 // reconnect and calls resetPasswordLifecycle().
176 void updatePasswordStatusOnDisconnected();
177
178 // This slot is called when the password has been accepted by the traffic
179 // data receiver. It emits a password storage request if appropriate and
180 // calls resetPasswordLifecycle().
181 void updatePasswordStatusOnHeartbeatChange(bool newHeartbeat);
182
183private:
184 Q_DISABLE_COPY_MOVE(TrafficDataSource_Tcp)
185
186 QTcpSocket m_socket;
187 QTextStream m_textStream;
188 QString m_hostName;
189 quint16 m_port;
190
191 // True while a connection is wanted. The socket's "disconnected" signal only
192 // triggers an automatic reconnect while this is true, so that
193 // disconnectFromTrafficReceiver() can actually stop the connection: abort()
194 // emits "disconnected", which would otherwise reconnect immediately.
195 bool m_connectionDesired = false;
196
197
198 /* Password lifecycle
199 *
200 * - The method onReadyRead detects that the device requests password. It
201 * will store the current SSID in passwordRequest_SSID and set
202 * passwordRequest_Status to waitingForPassword.
203 *
204 * - If a password for the SSID is found in the database, the method
205 * sendPassword is called with that password. Otherwise, the signal
206 * passwordRequest is emitted, which will hopefully lead to lead to a
207 * user-provided password through sendPassword()
208 *
209 * - The method send password will store the password in
210 * passwordRequest_password, send the password to the device and set
211 * passwordRequest_Status to waitingForDevice.
212 *
213 * - When the connection is closed while passwordRequest_Status ==
214 * waitingForDevice, this means that the traffic data receiver has
215 * rejected the password. The password stored in passwordRequest_password
216 * for passwordRequest_SSID is removed from the password database,
217 * passwordRequest_Status is set to idle, the members passwordRequest_SSID
218 * and passwordRequest_password are cleared and an immediate reconnect is
219 * scheduled.
220 *
221 * - When the heartbeat is received while passwordRequest_Status ==
222 * waitingForDevice, this means that the traffic data receiver has
223 * accepted the password. The instance will then emit the
224 * passwordStorageRequest. The member passwordRequest_Status is set to
225 * idle, and the members passwordRequest_SSID and passwordRequest_password
226 * are cleared.
227 */
228 enum : quint8 {
229 /* No password-related activity is pending */
230 idle,
231
232 /* Waiting for password
233 *
234 * A password has been requested by the traffic data receiver.
235 *
236 * At this stage, the member passwordRequest_SSID contains the network
237 * name of the WiFi network that the device was connected to at the
238 * time of the request.
239 */
240 waitingForPassword,
241
242 /* Waiting for device
243 *
244 * A password has been sent to the traffic data receiver, and this
245 * class is now waiting for the device to respond.
246 *
247 * At this stage, the member passwordRequest_SSID contains the network
248 * name of the WiFi network that the device was connected to at the
249 * time of the request. The member passwordRequest_password contains
250 * the password that has been sent to the traffic data receiver
251 */
252 waitingForDevice
253 } passwordRequest_Status {idle};
254
255 // See passwordRequest_Status documentation
256 QString passwordRequest_SSID;
257
258 // See passwordRequest_Status documentation
259 QString passwordRequest_password;
260};
261
262} // namespace Traffic
TrafficDataSource_AbstractSocket(bool isCanonical, QObject *parent)
Default constructor.
QString dataFormat() const override
Getter function for the property with the same name.
quint16 port() const
Getter function for the property with the same name.
void disconnectFromTrafficReceiver() override
Disconnect from traffic receiver.
TrafficDataSource_Tcp(bool isCanonical, QString hostName, quint16 port, QObject *parent=nullptr)
Default constructor.
void setPassword(const QString &SSID, const QString &password) override
Set password.
QString host() const
Getter function for the property with the same name.
QString icon() const override
Getter function for the property with the same name.
void connectToTrafficReceiver() override
Start attempt to connect to traffic receiver.
auto sourceName() const -> QString override
Getter function for the property with the same name.