25#include "moc_qgsiodevicesensor.cpp"
27using namespace Qt::StringLiterals;
29#if defined( Q_OS_ANDROID ) || defined( Q_OS_LINUX )
30#include <sys/socket.h>
39 mIODevice.reset( device );
49 return mIODevice.get();
55 data.lastValue = mIODevice->readAll();
56 data.lastTimestamp = QDateTime::currentDateTime();
64 , mTcpSocket( new QTcpSocket() )
66 connect( mTcpSocket, &QAbstractSocket::stateChanged,
this, &QgsTcpSocketSensor::socketStateChanged );
67 connect( mTcpSocket, qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ),
this, &QgsTcpSocketSensor::handleError );
79 return "tcp_socket"_L1;
110 if ( mHostName.isEmpty() || mPort == 0 )
116 mTcpSocket->connectToHost( mHostName, mPort, QTcpSocket::ReadOnly );
124void QgsTcpSocketSensor::handleError( QAbstractSocket::SocketError error )
128 case QAbstractSocket::HostNotFoundError:
131 case QAbstractSocket::NetworkError:
132 mErrorString = tr(
"Attempt to read or write from socket returned an error" );
134 case QAbstractSocket::ConnectionRefusedError:
135 mErrorString = tr(
"The connection was refused by the remote host" );
138 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
145void QgsTcpSocketSensor::socketStateChanged(
const QAbstractSocket::SocketState socketState )
147 switch ( socketState )
149 case QAbstractSocket::ConnectedState:
154 case QAbstractSocket::UnconnectedState:
166 element.setAttribute( u
"hostName"_s, mHostName );
167 element.setAttribute( u
"port"_s, QString::number( mPort ) );
174 mHostName = element.attribute( u
"hostName"_s );
175 mPort = element.attribute( u
"port"_s ).toInt();
184 , mUdpSocket( std::make_unique<QUdpSocket>() )
185 , mBuffer( new QBuffer() )
187#if defined( Q_OS_ANDROID ) || defined( Q_OS_LINUX )
188 int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
190 setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
191 (
void * ) &optval,
sizeof( optval ) );
192 mUdpSocket->setSocketDescriptor( sockfd, QUdpSocket::UnconnectedState );
195 connect( mUdpSocket.get(), &QAbstractSocket::stateChanged,
this, &QgsUdpSocketSensor::socketStateChanged );
196 connect( mUdpSocket.get(), &QUdpSocket::readyRead,
this, [
this]()
199 while ( mUdpSocket->hasPendingDatagrams() )
201 datagram.resize( int( mUdpSocket->pendingDatagramSize() ) );
202 mUdpSocket->readDatagram( datagram.data(), datagram.size() );
204 mBuffer->buffer().clear();
206 mBuffer->write( datagram );
211 connect( mUdpSocket.get(), qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ),
this, &QgsUdpSocketSensor::handleError );
213 initIODevice( mBuffer );
223 return "udp_socket"_L1;
254#ifdef QT_NO_NETWORKINTERFACE
255 Q_UNUSED( mHostName )
258 QgsDebugError( u
"Qt is built without network interface support, cannot use UDP sockets."_s );
260 if ( mHostName.isEmpty() || mPort == 0 )
266 mBuffer->open( QIODevice::ReadWrite );
267 mUdpSocket->bind( QHostAddress( mHostName ), mPort, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint );
268 mUdpSocket->joinMulticastGroup( QHostAddress( mHostName ) );
278void QgsUdpSocketSensor::handleError( QAbstractSocket::SocketError error )
282 case QAbstractSocket::HostNotFoundError:
285 case QAbstractSocket::NetworkError:
286 mErrorString = tr(
"Attempt to read or write from socket returned an error" );
288 case QAbstractSocket::ConnectionRefusedError:
289 mErrorString = tr(
"The connection was refused by the remote host" );
292 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
299void QgsUdpSocketSensor::socketStateChanged(
const QAbstractSocket::SocketState socketState )
301 switch ( socketState )
303 case QAbstractSocket::ConnectedState:
304 case QAbstractSocket::BoundState:
309 case QAbstractSocket::UnconnectedState:
321 element.setAttribute( u
"hostName"_s, mHostName );
322 element.setAttribute( u
"port"_s, QString::number( mPort ) );
329 mHostName = element.attribute( u
"hostName"_s );
330 mPort = element.attribute( u
"port"_s ).toInt();
337#if defined( HAVE_QTSERIALPORT )
338QgsSerialPortSensor::QgsSerialPortSensor( QObject *parent )
340 , mSerialPort( new QSerialPort() )
342 connect( mSerialPort, qOverload<QSerialPort::SerialPortError>( &QSerialPort::errorOccurred ),
this, &QgsSerialPortSensor::handleError );
347QgsSerialPortSensor *QgsSerialPortSensor::create( QObject *parent )
349 return new QgsSerialPortSensor( parent );
352QString QgsSerialPortSensor::type()
const
354 return "serial_port"_L1;
357QString QgsSerialPortSensor::portName()
const
362void QgsSerialPortSensor::setPortName(
const QString &portName )
364 if ( mPortName == portName )
367 mPortName = portName;
370QSerialPort::BaudRate QgsSerialPortSensor::baudRate()
const
375void QgsSerialPortSensor::setBaudRate(
const QSerialPort::BaudRate &baudRate )
377 if ( mBaudRate == baudRate )
380 mBaudRate = baudRate;
383QByteArray QgsSerialPortSensor::delimiter()
const
388void QgsSerialPortSensor::setDelimiter(
const QByteArray &delimiter )
390 if ( mDelimiter == delimiter )
393 mDelimiter = delimiter;
397void QgsSerialPortSensor::parseData()
399 if ( !mDelimiter.isEmpty() )
401 if ( mFirstDelimiterHit )
403 mDataBuffer += mSerialPort->readAll();
404 const auto lastIndex = mDataBuffer.lastIndexOf( mDelimiter );
405 if ( lastIndex > -1 )
408 data.
lastValue = mDataBuffer.mid( 0, lastIndex );
409 mDataBuffer = mDataBuffer.mid( lastIndex + mDelimiter.size() );
416 QByteArray data = mSerialPort->readAll();
417 const auto lastIndex = data.lastIndexOf( mDelimiter );
418 if ( lastIndex > -1 )
420 mFirstDelimiterHit =
true;
421 mDataBuffer = data.mid( lastIndex + mDelimiter.size() );
434void QgsSerialPortSensor::handleConnect()
436 mSerialPort->setPortName( mPortName );
437 mSerialPort->setBaudRate( mBaudRate );
438 mFirstDelimiterHit =
false;
440 if ( mSerialPort->open( QIODevice::ReadOnly ) )
450void QgsSerialPortSensor::handleDisconnect()
452 mSerialPort->close();
455void QgsSerialPortSensor::handleError( QSerialPort::SerialPortError error )
457 if ( error == QSerialPort::NoError )
464 case QSerialPort::DeviceNotFoundError:
465 mErrorString = tr(
"Could not find the serial port device" );
467 case QSerialPort::ReadError:
468 mErrorString = tr(
"Attempt to read from the serial port returned an error" );
470 case QSerialPort::PermissionError:
471 mErrorString = tr(
"The connection was refused due to not having enough permission" );
474 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QSerialPort::SerialPortError>().valueToKey( error ) );
478 emit errorOccurred( mErrorString );
481bool QgsSerialPortSensor::writePropertiesToElement( QDomElement &element, QDomDocument & )
const
483 element.setAttribute( u
"portName"_s, mPortName );
484 element.setAttribute( u
"baudRate"_s,
static_cast<int>( mBaudRate ) );
485 element.setAttribute( u
"delimiter"_s, QString( mDelimiter ) );
489bool QgsSerialPortSensor::readPropertiesFromElement(
const QDomElement &element,
const QDomDocument & )
491 mPortName = element.attribute( u
"portName"_s );
492 mBaudRate =
static_cast< QSerialPort::BaudRate
>( element.attribute( u
"baudRate"_s ).toInt() );
493 mDelimiter = element.attribute( u
"delimiter"_s ).toLocal8Bit();
@ Connected
Device is successfully connected.
@ Disconnected
Device is disconnected.
QgsAbstractSensor::SensorData data() const
Returns the latest captured data from the sensor.
void setStatus(Qgis::DeviceConnectionStatus status)
Sets the current sensor status.
void errorOccurred(const QString &errorString)
Emitted when an error has occurred. The errorString describes the error.
void setData(const QgsAbstractSensor::SensorData &data)
Sets the latest captured data from the sensor.
An abstract class for QIODevice-based sensors.
void initIODevice(QIODevice *device)
Initiates the I/O device.
QgsIODeviceSensor(QObject *parent=nullptr)
Constructor for a abstract QIODevice-based sensor, bound to the specified parent.
virtual void parseData()
Parses the data read from the device when available.
QIODevice * iODevice() const
Returns the I/O device.
~QgsIODeviceSensor() override
QgsTcpSocketSensor(QObject *parent=nullptr)
Constructor for a TCP socket sensor, bound to the specified parent.
void setHostName(const QString &hostName)
Sets the host name the socket connects to.
int port() const
Returns the port the socket connects to.
void handleConnect() override
Handles the connection to the sensor.
QString type() const override
Returns the sensor type.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document) const override
Write specific sensor type properties into a DOM element.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document) override
Restores specific sensor type properties from a DOM element.
void handleDisconnect() override
Handles the disconnection from the sensor.
static QgsTcpSocketSensor * create(QObject *parent)
Returns a new TCP socket sensor.
void setPort(int port)
Sets the port the socket connects to.
QString hostName() const
Returns the host name the socket connects to.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document) override
Restores specific sensor type properties from a DOM element.
static QgsUdpSocketSensor * create(QObject *parent)
Returns a new UDP socket sensor.
QString type() const override
Returns the sensor type.
void handleDisconnect() override
Handles the disconnection from the sensor.
QgsUdpSocketSensor(QObject *parent=nullptr)
Constructor for a UDP socket sensor, bound to the specified parent.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document) const override
Write specific sensor type properties into a DOM element.
void setHostName(const QString &hostName)
Sets the host name the socket connects to.
int port() const
Returns the port the socket connects to.
void handleConnect() override
Handles the connection to the sensor.
void setPort(int port)
Sets the port the socket connects to.
QString hostName() const
Returns the host name the socket connects to.
#define QgsDebugError(str)
Contains details of a sensor data capture.
QVariant lastValue
Last captured sensor value stored as a QVariant.
QDateTime lastTimestamp
Timestamp of last captured sensor value.