-
-
Notifications
You must be signed in to change notification settings - Fork 224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add egeniouss receiver. #5637
Add egeniouss receiver. #5637
Changes from 11 commits
aac7851
2f2e5e7
f02339a
084823b
76963a1
2009f87
7d9a9bc
089b1da
ee635cf
817566a
be89cc5
661a623
cd74cc9
deca732
65c6d8b
7330347
d30d81f
5c72442
ea00df0
781d9f9
183fd28
12f5ae5
d05d013
7020594
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#include "egenioussreceiver.h" | ||
|
||
#include <QHostAddress> | ||
#include <QJsonDocument> | ||
#include <QJsonValue> | ||
|
||
EgenioussReceiver::EgenioussReceiver( QObject *parent ) | ||
: AbstractGnssReceiver( parent ), mTcpSocket( new QTcpSocket( this ) ) | ||
{ | ||
connect( mTcpSocket, &QTcpSocket::readyRead, this, &EgenioussReceiver::onReadyRead ); | ||
connect( mTcpSocket, &QTcpSocket::errorOccurred, this, &EgenioussReceiver::onErrorOccurred ); | ||
connect( mTcpSocket, &QTcpSocket::connected, this, &EgenioussReceiver::connected ); | ||
connect( mTcpSocket, &QTcpSocket::disconnected, this, &EgenioussReceiver::disconnected ); | ||
} | ||
|
||
void EgenioussReceiver::handleConnectDevice() | ||
{ | ||
mTcpSocket->connectToHost( mAddress, mPort, QTcpSocket::ReadWrite ); | ||
} | ||
|
||
void EgenioussReceiver::connected() | ||
{ | ||
mSocketState = QAbstractSocket::ConnectedState; | ||
emit socketStateChanged( mSocketState ); | ||
} | ||
|
||
void EgenioussReceiver::handleDisconnectDevice() | ||
{ | ||
mTcpSocket->disconnectFromHost(); | ||
} | ||
|
||
void EgenioussReceiver::disconnected() | ||
{ | ||
if ( mTcpSocket->state() == QAbstractSocket::ConnectedState ) | ||
{ | ||
mSocketState = QAbstractSocket::UnconnectedState; | ||
emit socketStateChanged( mSocketState ); | ||
} | ||
} | ||
|
||
QList<QPair<QString, QVariant>> EgenioussReceiver::details() | ||
domi4484 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
QList<QPair<QString, QVariant>> detailsList; | ||
|
||
if ( mPayload.isEmpty() ) | ||
{ | ||
return detailsList; | ||
} | ||
|
||
detailsList.append( qMakePair( "q", mPayload.value( "q" ).toString() ) ); | ||
|
||
return detailsList; | ||
} | ||
|
||
void EgenioussReceiver::onReadyRead() | ||
{ | ||
QByteArray mReceivedData = mTcpSocket->readAll(); | ||
if ( mReceivedData.size() < 9 ) | ||
nirvn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return; // Received data is too short to process. | ||
nirvn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if ( static_cast<uint8_t>( mReceivedData[0] ) != 0xFE ) | ||
{ | ||
return; // Invalid start byte | ||
nirvn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
uint32_t payloadLength; | ||
QDataStream dataStream( mReceivedData.mid( 4, 4 ) ); | ||
dataStream.setByteOrder( QDataStream::LittleEndian ); | ||
dataStream >> payloadLength; | ||
if ( mReceivedData.size() < 8 + payloadLength ) | ||
{ | ||
return; // Received data is too short to contain the payload. | ||
} | ||
QJsonDocument jsonDoc = QJsonDocument::fromJson( mReceivedData.mid( 8, payloadLength ) ); | ||
if ( jsonDoc.isNull() || !jsonDoc.isObject() ) | ||
{ | ||
return; // Failed to parse JSON | ||
} | ||
mPayload = jsonDoc.object(); | ||
const double latitude = mPayload.value( "lat" ).toDouble() == 0 ? std::numeric_limits<double>::quiet_NaN() : mPayload.value( "lat" ).toDouble(); | ||
const double longitude = mPayload.value( "lon" ).toDouble() == 0 ? std::numeric_limits<double>::quiet_NaN() : mPayload.value( "lon" ).toDouble(); | ||
const double elevation = mPayload.value( "alt" ).toDouble() == 0 ? std::numeric_limits<double>::quiet_NaN() : mPayload.value( "alt" ).toDouble(); | ||
mLastGnssPositionInformation = GnssPositionInformation( | ||
latitude, | ||
longitude, | ||
elevation, | ||
std::numeric_limits<double>::quiet_NaN(), | ||
std::numeric_limits<double>::quiet_NaN(), | ||
QList<QgsSatelliteInfo>(), | ||
0, | ||
0, | ||
0, | ||
std::numeric_limits<double>::quiet_NaN(), | ||
std::numeric_limits<double>::quiet_NaN(), | ||
QDateTime::fromMSecsSinceEpoch( mPayload.value( "utc" ).toDouble() / 1e6, Qt::UTC ), | ||
QChar(), | ||
0, | ||
1 ); | ||
|
||
emit lastGnssPositionInformationChanged( mLastGnssPositionInformation ); | ||
} | ||
|
||
void EgenioussReceiver::onErrorOccurred( QAbstractSocket::SocketError socketError ) | ||
{ | ||
mLastError = mTcpSocket->errorString(); | ||
emit lastErrorChanged( mLastError ); | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would move this class to an egeniouss directory inside positioning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @domi4484 , let's maybe not do this right away. ATM we have our other device classes sitting in positioning (Bluetooth, TCP, UDP, serial) here and having a directory for a single pair of .CPP, .H feels a bit too much. If we end up needing another class (eg egenioussutils) let's maybe consider moving all of it into an src/core/egeniouss directory) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#pragma once | ||
nirvn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#include "abstractgnssreceiver.h" | ||
|
||
#include <QJsonObject> | ||
#include <QTcpSocket> | ||
|
||
class EgenioussReceiver : public AbstractGnssReceiver | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
explicit EgenioussReceiver( QObject *parent = nullptr ); | ||
|
||
private: | ||
void handleConnectDevice() override; | ||
void handleDisconnectDevice() override; | ||
QList<QPair<QString, QVariant>> details() override; | ||
|
||
private slots: | ||
void onReadyRead(); | ||
void onErrorOccurred( QAbstractSocket::SocketError socketError ); | ||
|
||
private: | ||
void processReceivedData(); | ||
void connected(); | ||
void disconnected(); | ||
|
||
private: | ||
QTcpSocket *mTcpSocket = nullptr; | ||
QJsonObject mPayload; | ||
const QHostAddress::SpecialAddress mAddress = QHostAddress::LocalHost; | ||
const int mPort = 1235; | ||
}; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would put this file into a egeniouss directory. Maybe into positioning/egeniouss and move as well other positioning related files in there to gain some structure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest this structural change be kept in a separate PR |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import QtQuick | ||
import QtQuick.Controls | ||
import QtQuick.Layouts | ||
import org.qfield | ||
import Theme | ||
|
||
Item { | ||
width: parent.width | ||
|
||
property alias deviceAddress: egenioussDeviceAddress.text | ||
property alias devicePort: egenioussDevicePort.text | ||
|
||
function generateName() { | ||
return deviceAddress + ' (' + devicePort + ')'; | ||
} | ||
|
||
function setSettings(settings) { | ||
deviceAddress = settings['address']; | ||
devicePort = settings['port']; | ||
} | ||
|
||
function getSettings() { | ||
return { | ||
"address": deviceAddress.trim(), | ||
"port": parseInt(devicePort) | ||
}; | ||
} | ||
|
||
GridLayout { | ||
width: parent.width | ||
columns: 1 | ||
columnSpacing: 0 | ||
rowSpacing: 5 | ||
|
||
Label { | ||
Layout.fillWidth: true | ||
text: qsTr("Address:") | ||
font: Theme.defaultFont | ||
wrapMode: Text.WordWrap | ||
} | ||
|
||
QfTextField { | ||
id: egenioussDeviceAddress | ||
Layout.fillWidth: true | ||
font: Theme.defaultFont | ||
text: '127.0.0.1' | ||
inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase | ||
} | ||
|
||
Label { | ||
Layout.fillWidth: true | ||
text: qsTr("Port:") | ||
font: Theme.defaultFont | ||
wrapMode: Text.WordWrap | ||
} | ||
|
||
QfTextField { | ||
id: egenioussDevicePort | ||
Layout.fillWidth: true | ||
font: Theme.defaultFont | ||
text: '1235' | ||
inputMethodHints: Qt.ImhFormattedNumbersOnly | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels a bit strange to me that subclasses of postioning device have to manage
mSocketState
that way. mSocketState and mSocketStateString have a quite risk to get out of sync. Wouldn't be it a cleaner interface to reimplementAbstractGnssReceiver::socketState()
andsocketStateString
in subclasses and get rid of the variables mSocketState and mSocketStateString?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@domi4484 , not a bad idea. Can we do that in a follow up PR?