24#include "moc_qgsiodevicesensor.cpp"
26#if defined( Q_OS_ANDROID ) || defined( Q_OS_LINUX )
27#include <sys/socket.h>
36 mIODevice.reset( device );
46 return mIODevice.get();
52 data.lastValue = mIODevice->readAll();
53 data.lastTimestamp = QDateTime::currentDateTime();
61 , mTcpSocket( new QTcpSocket() )
63 connect( mTcpSocket, &QAbstractSocket::stateChanged,
this, &QgsTcpSocketSensor::socketStateChanged );
64 connect( mTcpSocket, qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ),
this, &QgsTcpSocketSensor::handleError );
76 return "tcp_socket"_L1;
107 if ( mHostName.isEmpty() || mPort == 0 )
113 mTcpSocket->connectToHost( mHostName, mPort, QTcpSocket::ReadOnly );
121void QgsTcpSocketSensor::handleError( QAbstractSocket::SocketError error )
125 case QAbstractSocket::HostNotFoundError:
128 case QAbstractSocket::NetworkError:
129 mErrorString = tr(
"Attempt to read or write from socket returned an error" );
131 case QAbstractSocket::ConnectionRefusedError:
132 mErrorString = tr(
"The connection was refused by the remote host" );
135 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
142void QgsTcpSocketSensor::socketStateChanged(
const QAbstractSocket::SocketState socketState )
144 switch ( socketState )
146 case QAbstractSocket::ConnectedState:
151 case QAbstractSocket::UnconnectedState:
163 element.setAttribute( u
"hostName"_s, mHostName );
164 element.setAttribute( u
"port"_s, QString::number( mPort ) );
171 mHostName = element.attribute( u
"hostName"_s );
172 mPort = element.attribute( u
"port"_s ).toInt();
181 , mUdpSocket( std::make_unique<QUdpSocket>() )
182 , mBuffer( new QBuffer() )
184#if defined( Q_OS_ANDROID ) || defined( Q_OS_LINUX )
185 int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
187 setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
188 (
void * ) &optval,
sizeof( optval ) );
189 mUdpSocket->setSocketDescriptor( sockfd, QUdpSocket::UnconnectedState );
192 connect( mUdpSocket.get(), &QAbstractSocket::stateChanged,
this, &QgsUdpSocketSensor::socketStateChanged );
193 connect( mUdpSocket.get(), &QUdpSocket::readyRead,
this, [
this]()
196 while ( mUdpSocket->hasPendingDatagrams() )
198 datagram.resize( int( mUdpSocket->pendingDatagramSize() ) );
199 mUdpSocket->readDatagram( datagram.data(), datagram.size() );
201 mBuffer->buffer().clear();
203 mBuffer->write( datagram );
208 connect( mUdpSocket.get(), qOverload<QAbstractSocket::SocketError>( &QAbstractSocket::errorOccurred ),
this, &QgsUdpSocketSensor::handleError );
210 initIODevice( mBuffer );
220 return "udp_socket"_L1;
251#ifdef QT_NO_NETWORKINTERFACE
252 Q_UNUSED( mHostName )
255 QgsDebugError( u
"Qt is built without network interface support, cannot use UDP sockets."_s );
257 if ( mHostName.isEmpty() || mPort == 0 )
263 mBuffer->open( QIODevice::ReadWrite );
264 mUdpSocket->bind( QHostAddress( mHostName ), mPort, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint );
265 mUdpSocket->joinMulticastGroup( QHostAddress( mHostName ) );
275void QgsUdpSocketSensor::handleError( QAbstractSocket::SocketError error )
279 case QAbstractSocket::HostNotFoundError:
282 case QAbstractSocket::NetworkError:
283 mErrorString = tr(
"Attempt to read or write from socket returned an error" );
285 case QAbstractSocket::ConnectionRefusedError:
286 mErrorString = tr(
"The connection was refused by the remote host" );
289 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( error ) );
296void QgsUdpSocketSensor::socketStateChanged(
const QAbstractSocket::SocketState socketState )
298 switch ( socketState )
300 case QAbstractSocket::ConnectedState:
301 case QAbstractSocket::BoundState:
306 case QAbstractSocket::UnconnectedState:
318 element.setAttribute( u
"hostName"_s, mHostName );
319 element.setAttribute( u
"port"_s, QString::number( mPort ) );
326 mHostName = element.attribute( u
"hostName"_s );
327 mPort = element.attribute( u
"port"_s ).toInt();
334#if defined( HAVE_QTSERIALPORT )
335QgsSerialPortSensor::QgsSerialPortSensor( QObject *parent )
337 , mSerialPort( new QSerialPort() )
339 connect( mSerialPort, qOverload<QSerialPort::SerialPortError>( &QSerialPort::errorOccurred ),
this, &QgsSerialPortSensor::handleError );
344QgsSerialPortSensor *QgsSerialPortSensor::create( QObject *parent )
346 return new QgsSerialPortSensor( parent );
349QString QgsSerialPortSensor::type()
const
351 return "serial_port"_L1;
354QString QgsSerialPortSensor::portName()
const
359void QgsSerialPortSensor::setPortName(
const QString &portName )
361 if ( mPortName == portName )
364 mPortName = portName;
367QSerialPort::BaudRate QgsSerialPortSensor::baudRate()
const
372void QgsSerialPortSensor::setBaudRate(
const QSerialPort::BaudRate &baudRate )
374 if ( mBaudRate == baudRate )
377 mBaudRate = baudRate;
380QByteArray QgsSerialPortSensor::delimiter()
const
385void QgsSerialPortSensor::setDelimiter(
const QByteArray &delimiter )
387 if ( mDelimiter == delimiter )
390 mDelimiter = delimiter;
394void QgsSerialPortSensor::parseData()
396 if ( !mDelimiter.isEmpty() )
398 if ( mFirstDelimiterHit )
400 mDataBuffer += mSerialPort->readAll();
401 const auto lastIndex = mDataBuffer.lastIndexOf( mDelimiter );
402 if ( lastIndex > -1 )
405 data.
lastValue = mDataBuffer.mid( 0, lastIndex );
406 mDataBuffer = mDataBuffer.mid( lastIndex + mDelimiter.size() );
413 QByteArray data = mSerialPort->readAll();
414 const auto lastIndex = data.lastIndexOf( mDelimiter );
415 if ( lastIndex > -1 )
417 mFirstDelimiterHit =
true;
418 mDataBuffer = data.mid( lastIndex + mDelimiter.size() );
431void QgsSerialPortSensor::handleConnect()
433 mSerialPort->setPortName( mPortName );
434 mSerialPort->setBaudRate( mBaudRate );
435 mFirstDelimiterHit =
false;
437 if ( mSerialPort->open( QIODevice::ReadOnly ) )
447void QgsSerialPortSensor::handleDisconnect()
449 mSerialPort->close();
452void QgsSerialPortSensor::handleError( QSerialPort::SerialPortError error )
454 if ( error == QSerialPort::NoError )
461 case QSerialPort::DeviceNotFoundError:
462 mErrorString = tr(
"Could not find the serial port device" );
464 case QSerialPort::ReadError:
465 mErrorString = tr(
"Attempt to read from the serial port returned an error" );
467 case QSerialPort::PermissionError:
468 mErrorString = tr(
"The connection was refused due to not having enough permission" );
471 mErrorString = tr(
"%1" ).arg( QMetaEnum::fromType<QSerialPort::SerialPortError>().valueToKey( error ) );
475 emit errorOccurred( mErrorString );
478bool QgsSerialPortSensor::writePropertiesToElement( QDomElement &element, QDomDocument & )
const
480 element.setAttribute( u
"portName"_s, mPortName );
481 element.setAttribute( u
"baudRate"_s,
static_cast<int>( mBaudRate ) );
482 element.setAttribute( u
"delimiter"_s, QString( mDelimiter ) );
486bool QgsSerialPortSensor::readPropertiesFromElement(
const QDomElement &element,
const QDomDocument & )
488 mPortName = element.attribute( u
"portName"_s );
489 mBaudRate =
static_cast< QSerialPort::BaudRate
>( element.attribute( u
"baudRate"_s ).toInt() );
490 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.