summaryrefslogtreecommitdiff
path: root/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2019-04-05 12:36:22 +0200
committerpaolo <paolo.angelelli@qt.io>2019-08-09 13:49:42 +0200
commit3334c6f6d00255f6fd5690e4b9cb05416950fd4d (patch)
tree601dbf9cd3ac8ea2e500409a5c9ec90214580289 /src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp
parent0a242cc026190432a115a82752ddf35b8be15de6 (diff)
downloadqtlocation-3334c6f6d00255f6fd5690e4b9cb05416950fd4d.tar.gz
Introduce QIOPipe and use it in serialnmea plugin
This allows the plugin to pipe the input stream into multiple, independent processing pipelines. Good for allowing multiple position sources from the same serial port, and will allow supporting satellite info source in the nmea plugin too. Change-Id: I21e3cd2c78e7138ca49821c68b55ce96eb83e986 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp')
-rw-r--r--src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp100
1 files changed, 80 insertions, 20 deletions
diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp
index 043f7682..bebf7230 100644
--- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp
+++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp
@@ -43,34 +43,100 @@
#include <QtSerialPort/qserialportinfo.h>
#include <QtCore/qloggingcategory.h>
#include <QSet>
+#include "qiopipe_p.h"
+#include <QSharedPointer>
Q_LOGGING_CATEGORY(lcSerial, "qt.positioning.serialnmea")
+class IODeviceContainer
+{
+public:
+ IODeviceContainer() {}
+ IODeviceContainer(IODeviceContainer const&) = delete;
+ void operator=(IODeviceContainer const&) = delete;
+
+ QSharedPointer<QIOPipe> serial(const QString &portName)
+ {
+ if (m_serialPorts.contains(portName)) {
+ m_serialPorts[portName].refs++;
+ QIOPipe *endPipe = new QIOPipe(m_serialPorts[portName].proxy);
+ m_serialPorts[portName].proxy->addChildPipe(endPipe);
+ return QSharedPointer<QIOPipe>(endPipe);
+ }
+ IODevice device;
+ QSerialPort *port = new QSerialPort(portName);
+ port->setBaudRate(4800);
+ qCDebug(lcSerial) << "Opening serial port" << portName;
+ if (!port->open(QIODevice::ReadOnly)) {
+ qWarning("serialnmea: Failed to open %s", qPrintable(portName));
+ delete port;
+ return {};
+ }
+ qCDebug(lcSerial) << "Opened successfully";
+ device.device = port;
+ device.refs = 1;
+ device.proxy = new QIOPipe(port, QIOPipe::ProxyPipe);
+ m_serialPorts[portName] = device;
+ QIOPipe *endPipe = new QIOPipe(device.proxy);
+ device.proxy->addChildPipe(endPipe);
+ return QSharedPointer<QIOPipe>(endPipe);
+ }
+
+ void releaseSerial(const QString &portName, QSharedPointer<QIOPipe> &pipe) {
+ if (!m_serialPorts.contains(portName))
+ return;
+
+ pipe.clear(); // make sure to release the pipe returned by getSerial, or else, if there are still refs, data will be leaked through it
+ IODevice &device = m_serialPorts[portName];
+ if (device.refs > 1) {
+ device.refs--;
+ return;
+ }
+
+ IODevice taken = m_serialPorts.take(portName);
+ taken.device->deleteLater();
+ }
+
+private:
+
+ struct IODevice {
+ QIODevice *device = nullptr;
+ QIOPipe *proxy = nullptr; // adding client pipes as children of proxy allows to dynamically add clients to one device.
+ unsigned int refs = 1;
+ };
+
+ QMap<QString, IODevice> m_serialPorts;
+};
+
+Q_GLOBAL_STATIC(IODeviceContainer, deviceContainer)
+
+
class NmeaSource : public QNmeaPositionInfoSource
{
public:
- NmeaSource(QObject *parent, const QVariantMap &parameters);
+ explicit NmeaSource(QObject *parent, const QVariantMap &parameters);
+ ~NmeaSource() override;
bool isValid() const { return !m_port.isNull(); }
private:
- QScopedPointer<QSerialPort> m_port;
+ QSharedPointer<QIOPipe> m_port;
+ QString m_portName;
};
NmeaSource::NmeaSource(QObject *parent, const QVariantMap &parameters)
- : QNmeaPositionInfoSource(RealTimeMode, parent),
- m_port(new QSerialPort)
+ : QNmeaPositionInfoSource(RealTimeMode, parent)
{
QByteArray requestedPort;
if (parameters.contains(QStringLiteral("serialnmea.serial_port")))
requestedPort = parameters.value(QStringLiteral("serialnmea.serial_port")).toString().toLatin1();
else
requestedPort = qgetenv("QT_NMEA_SERIAL_PORT");
+ QString portName;
if (requestedPort.isEmpty()) {
const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
qCDebug(lcSerial) << "Found" << ports.count() << "serial ports";
if (ports.isEmpty()) {
qWarning("serialnmea: No serial ports found");
- m_port.reset();
return;
}
@@ -78,8 +144,7 @@ NmeaSource::NmeaSource(QObject *parent, const QVariantMap &parameters)
QSet<int> supportedDevices;
supportedDevices << 0x67b; // GlobalSat (BU-353S4 and probably others)
supportedDevices << 0xe8d; // Qstarz MTK II
- QString portName;
- foreach (const QSerialPortInfo& port, ports) {
+ for (const QSerialPortInfo& port : ports) {
if (port.hasVendorIdentifier() && supportedDevices.contains(port.vendorIdentifier())) {
portName = port.portName();
break;
@@ -88,28 +153,23 @@ NmeaSource::NmeaSource(QObject *parent, const QVariantMap &parameters)
if (portName.isEmpty()) {
qWarning("serialnmea: No known GPS device found. Specify the COM port via QT_NMEA_SERIAL_PORT.");
- m_port.reset();
return;
}
-
- m_port->setPortName(portName);
+ m_portName = portName;
} else {
- m_port->setPortName(QString::fromUtf8(requestedPort));
+ m_portName = QString::fromUtf8(requestedPort);
}
- m_port->setBaudRate(4800);
-
- qCDebug(lcSerial) << "Opening serial port" << m_port->portName();
-
- if (!m_port->open(QIODevice::ReadOnly)) {
- qWarning("serialnmea: Failed to open %s", qPrintable(m_port->portName()));
- m_port.reset();
+ m_port = deviceContainer->serial(m_portName);
+ if (!m_port)
return;
- }
setDevice(m_port.data());
+}
- qCDebug(lcSerial) << "Opened successfully";
+NmeaSource::~NmeaSource()
+{
+ deviceContainer->releaseSerial(m_portName, m_port);
}
QGeoPositionInfoSource *QGeoPositionInfoSourceFactorySerialNmea::positionInfoSource(QObject *parent)