Add memory sqlite db for cluster spots.

knobtest
Phil Taylor 2022-10-05 11:03:15 +01:00
rodzic 9db695cc63
commit 711b86e91b
8 zmienionych plików z 308 dodań i 79 usunięć

Wyświetl plik

@ -13,6 +13,8 @@ dxClusterClient::~dxClusterClient()
qInfo(logCluster()) << "closing dxClusterClient()";
enableUdp(false);
enableTcp(false);
database db;
db.close();
}
void dxClusterClient::enableUdp(bool enable)
@ -27,7 +29,6 @@ void dxClusterClient::enableUdp(bool enable)
qInfo(logCluster()) << "Starting udpSocket() on:" << udpPort << "Result:" << result;
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(udpDataReceived()), Qt::QueuedConnection);
}
}
else {
@ -56,6 +57,7 @@ void dxClusterClient::enableTcp(bool enable)
qInfo(logCluster()) << "Starting tcpSocket() on:" << tcpPort;
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(tcpDataReceived()), Qt::QueuedConnection);
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
tcpCleanupTimer = new QTimer(this);
tcpCleanupTimer->setInterval(1000 * 10); // Run once a minute
@ -76,7 +78,7 @@ void dxClusterClient::enableTcp(bool enable)
tcpSocket->disconnect();
delete tcpSocket;
tcpSocket = Q_NULLPTR;
emit deleteOldSpots(0);
//emit deleteOldSpots(0);
}
}
}
@ -104,17 +106,26 @@ void dxClusterClient::udpDataReceived()
data->timestamp = QDateTime::fromString(spot.firstChildElement("timestamp").text(),"yyyy-MM-dd hh:mm:ss");
data->mode = spot.firstChildElement("mode").text();
data->comment = spot.firstChildElement("comment").text();
emit addSpot(data);
emit(sendOutput(QString("UDP: SPOT:%1 SPOTTER:%2 FREQ:%3 MODE:%4 DATE:%5 COMMENT:%6\n")
.arg(data->dxcall).arg(data->spottercall).arg(data->frequency).arg(data->mode)
.arg(data->timestamp.toString()).arg(data->comment)));
//emit addSpot(data);
database db = database();
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,mode,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6','%7')\n")
.arg("UDP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->mode).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
db.query(query);
emit sendOutput(query);
}
else if (action == "delete")
{
QString dxcall = spot.firstChildElement("dxcall").text();
emit deleteSpot(dxcall);
qInfo(logCluster()) << "DELETE DX=" << dxcall;
double frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
//emit deleteSpot(dxcall);
database db = database();
QString query=QString("DELETE from spots where dxcall='%1' AND frequency=%2").arg(dxcall).arg(frequency);
db.query(query);
qInfo(logCluster()) << query;
}
updateSpots();
}
}
}
@ -140,17 +151,21 @@ void dxClusterClient::tcpDataReceived()
if (match.hasMatch()) {
spotData* data = new spotData();
data->spottercall = match.captured(1);
data->frequency = match.captured(2).toFloat() / 1000.0;
data->frequency = match.captured(2).toDouble() / 1000.0;
data->dxcall = match.captured(3);
data->comment = match.captured(4).trimmed();
data->timestamp = QDateTime::currentDateTimeUtc();
//data.timestamp = QDateTime::fromString(match.captured(5), "hhmmZ");
emit addSpot(data);
emit(sendOutput(QString("TCP: SPOT:%1 SPOTTER:%2 FREQ:%3 MODE:%4 DATE:%5 COMMENT:%6\n")
.arg(data->dxcall).arg(data->spottercall).arg(data->frequency).arg(data->mode)
.arg(data->timestamp.toString()).arg(data->comment)));
//emit addSpot(data);
database db = database();
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6')\n")
.arg("TCP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
db.query(query);
emit sendOutput(query);
}
}
updateSpots();
}
@ -169,5 +184,39 @@ void dxClusterClient::sendTcpData(QString data)
void dxClusterClient::tcpCleanup()
{
emit deleteOldSpots(tcpTimeout);
}
//emit deleteOldSpots(tcpTimeout);
database db = database();
db.query(QString("DELETE FROM spots where timestamp < datetime('now', '-%1 minutes')").arg(tcpTimeout));
}
void dxClusterClient::tcpDisconnected() {
qWarning(logCluster()) << "TCP Cluster server disconnected...";
// Need to start a timer and attempt reconnect.
}
void dxClusterClient::freqRange(double low, double high)
{
lowFreq = low;
highFreq = high;
//qInfo(logCluster) << "New range" << low << "-" << high;
updateSpots();
}
void dxClusterClient::updateSpots()
{
// Set the required freqency range.
QString queryText = QString("SELECT * FROM spots WHERE frequency >= %1 AND frequency <= %2").arg(lowFreq).arg(highFreq);
//QString queryText = QString("SELECT * FROM spots");
database db;
auto query = db.query(queryText);
QList<spotData> spots;
while (query.next()) {
// Step through all current spots within range
spotData s = spotData();
s.dxcall = query.value(query.record().indexOf("dxcall")).toString();
s.frequency = query.value(query.record().indexOf("frequency")).toDouble();
spots.append(s);
}
emit sendSpots(spots);
}

Wyświetl plik

@ -11,7 +11,10 @@
#include <QDateTime>
#include <QRegularExpression>
#include <QTimer>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <qcustomplot.h>
#include "database.h"
struct spotData {
QString dxcall;
@ -21,6 +24,7 @@ struct spotData {
QString mode;
QString comment;
QCPItemText* text = Q_NULLPTR;
bool current = false;
};
struct clusterSettings {
@ -45,10 +49,12 @@ signals:
void deleteSpot(QString dxcall);
void deleteOldSpots(int minutes);
void sendOutput(QString text);
void sendSpots(QList<spotData> spots);
public slots:
void udpDataReceived();
void tcpDataReceived();
void tcpDisconnected();
void enableUdp(bool enable);
void enableTcp(bool enable);
void setUdpPort(int p) { udpPort = p; }
@ -58,9 +64,12 @@ public slots:
void setTcpPassword(QString s) { tcpPassword = s; }
void setTcpTimeout(int p) { tcpTimeout = p; }
void tcpCleanup();
void freqRange(double low, double high);
private:
void sendTcpData(QString data);
bool databaseOpen();
void updateSpots();
bool udpEnable;
bool tcpEnable;
@ -77,6 +86,9 @@ private:
QMutex mutex;
bool authenticated=false;
QTimer* tcpCleanupTimer=Q_NULLPTR;
QSqlDatabase db;
double lowFreq;
double highFreq;
};
#endif

103
database.cpp 100644
Wyświetl plik

@ -0,0 +1,103 @@
#include "database.h"
#include "logcategories.h"
database::database()
{
open();
}
database::~database()
{
}
bool database::open()
{
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
if (QSqlDatabase::contains(name))
{
db = QSqlDatabase::database(name);
qu = QSqlQuery(db);
return true;
}
else {
qInfo(logCluster()) << "Creating new connection" << name;
db = QSqlDatabase::addDatabase("QSQLITE", name);
qu = QSqlQuery(db);
}
//QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + "wfview.db";
QString path = ":memory:";
qInfo(logCluster()) << "DB Filename" << path;
db.setDatabaseName(path);
if (db.isValid())
{
db.open();
if (check()) {
return true;
}
}
qWarning(logCluster()) << "Database is not valid!";
return false;
}
void database::close()
{
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
qInfo(logCluster()) << "Closing database connection:" << name;
db.close();
}
QSqlQuery database::query(QString query)
{
if (!db.isOpen())
{
qWarning(logCluster()) << "Query Database is not open!";
db.open();
}
qu.exec(query);
return qu;
}
bool database::check()
{
if (db.isOpen()) {
for (const auto& table : db.tables())
{
if (table == "spots")
{
qInfo(logCluster()) << "DB Contains spots table";
return true;
}
}
qInfo(logCluster()) << "Creating spots table";
// Spots table does not exist, need to create it.
/*
QString dxcall;
double frequency;
QString spottercall;
QDateTime timestamp;
QString mode;
QString comment;
QCPItemText* text = Q_NULLPTR;*/
qu.exec("CREATE TABLE spots "
"(id INTEGER PRIMARY KEY, "
"type VARCHAR(3),"
"dxcall VARCHAR(30),"
"spottercall VARCHAR(30),"
"frequency DOUBLE,"
"timestamp DATETIME,"
"mode VARCHAR(30),"
"comment VARCHAR(255) )");
qu.exec("CREATE INDEX spots_index ON spots(type,dxcall,frequency,timestamp)");
return true;
}
else {
qWarning(logCluster()) << "Database is not open";
}
return false;
}

34
database.h 100644
Wyświetl plik

@ -0,0 +1,34 @@
#ifndef DATABASE_H
#define DATABASE_H
#include <QObject>
#include <QDebug>
#include <QDateTime>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlResult>
#include <QThread>
#include <QStandardPaths>
class database
{
public:
explicit database();
virtual ~database();
bool open();
void close();
QSqlQuery query(QString query);
QSqlResult database::get();
signals:
public slots:
private:
bool check();
QSqlDatabase db;
QSqlQuery qu;
};
#endif

Wyświetl plik

@ -69,9 +69,10 @@ wfmain::wfmain(const QString settingsFile, const QString logFile, bool debugMode
qRegisterMetaType <datekind>();
qRegisterMetaType<rigstate*>();
qRegisterMetaType<QList<radio_cap_packet>>();
qRegisterMetaType<QList<radio_cap_packet>>();
qRegisterMetaType<QList<spotData>>();
qRegisterMetaType<networkStatus>();
qRegisterMetaType<networkAudioLevels>();
qRegisterMetaType<spotData>();
haveRigCaps = false;
@ -125,10 +126,9 @@ wfmain::wfmain(const QString settingsFile, const QString logFile, bool debugMode
connect(this, SIGNAL(setClusterUserName(QString)), cluster, SLOT(setTcpUserName(QString)));
connect(this, SIGNAL(setClusterPassword(QString)), cluster, SLOT(setTcpPassword(QString)));
connect(this, SIGNAL(setClusterTimeout(int)), cluster, SLOT(setTcpTimeout(int)));
connect(this, SIGNAL(setFrequencyRange(double, double)), cluster, SLOT(freqRange(double, double)));
connect(cluster, SIGNAL(addSpot(spotData*)), this, SLOT(addClusterSpot(spotData*)));
connect(cluster, SIGNAL(deleteSpot(QString)), this, SLOT(deleteClusterSpot(QString)));
connect(cluster, SIGNAL(deleteOldSpots(int)), this, SLOT(deleteOldClusterSpots(int)));
connect(cluster, SIGNAL(sendSpots(QList<spotData>)), this, SLOT(receiveSpots(QList<spotData>)));
connect(cluster, SIGNAL(sendOutput(QString)), this, SLOT(receiveClusterOutput(QString)));
connect(clusterThread, SIGNAL(finished()), cluster, SLOT(deleteLater()));
@ -3855,6 +3855,8 @@ void wfmain::receiveSpectrumData(QByteArray spectrum, double startFreq, double e
// This will break if the button is ever moved or renamed.
on_clearPeakBtn_clicked();
}
// Inform other threads (cluster) that the frequency range has changed.
emit setFrequencyRange(startFreq, endFreq);
// TODO: Add clear-out for the buffer
}
@ -4117,7 +4119,7 @@ void wfmain::handleWFDoubleClick(QMouseEvent *me)
}
}
void wfmain::handlePlotClick(QMouseEvent *me)
void wfmain::handlePlotClick(QMouseEvent* me)
{
double x = plot->xAxis->pixelToCoord(me->pos().x());
showStatusBarText(QString("Selected %1 MHz").arg(x));
@ -7499,42 +7501,6 @@ void wfmain::receiveClusterOutput(QString text) {
ui->clusterOutputTextEdit->moveCursor(QTextCursor::End);
}
void wfmain::addClusterSpot(spotData* s) {
s->text = new QCPItemText(plot);
s->text->setAntialiased(true);
s->text->setColor(QColor(Qt::red));
s->text->setText(s->dxcall);
s->text->setFont(QFont(font().family(), 10));
s->text->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter);
//s->text->setClipAxisRect(false);
s->text->position->setType(QCPItemPosition::ptPlotCoords);
//bool conflict = true;
//QCPAxisRect* rect = spot.text->position->axisRect();
double left = s->frequency;
double top = rigCaps.spectAmpMax - 50.0;
s->text->position->setCoords(left, top);
//QList<QGraphicsItem*> col_it = spot.text->item(Qt::IntersectsItemBoundingRect);
QMutexLocker locker(&clusterMutex);
clusterSpots.insert(s->dxcall, s);
//qInfo(logGui()) << "Number of cluster spots" << clusterSpots.size();
}
void wfmain::deleteClusterSpot(QString dxcall) {
QMutexLocker locker(&clusterMutex);
QMap<QString, spotData*>::iterator spot = clusterSpots.find(dxcall);
while (spot != clusterSpots.end() && spot.key() == dxcall) {
if (spot.value()->text != Q_NULLPTR)
{
plot->removeItem(spot.value()->text);
}
delete spot.value();
spot = clusterSpots.erase(spot);
}
}
void wfmain::on_clusterUdpEnable_clicked(bool enable)
{
prefs.clusterUdpEnable = enable;
@ -7661,26 +7627,86 @@ void wfmain::on_clusterTimeoutLineEdit_editingFinished()
}
void wfmain::deleteOldClusterSpots(int timeout)
void wfmain::receiveSpots(QList<spotData> spots)
{
QMutexLocker locker(&clusterMutex);
QDateTime time=QDateTime::currentDateTimeUtc();
//qDebug(logGui()) << "Deleting old Cluster spots";
QMap<QString, spotData*>::iterator spot = clusterSpots.begin();
while (spot != clusterSpots.end()) {
if (spot.value()->timestamp.addSecs(timeout * 60) < time) {
if (spot.value()->text != Q_NULLPTR)
{
plot->removeItem(spot.value()->text);
}
//qDebug(logGui()) << "Deleting:" << spot.value()->dxcall << "Timestamp" << spot.value()->timestamp.addSecs(timeout * 60) << "is lower than" << time;
delete spot.value(); // Stop memory leak?
spot = clusterSpots.erase(spot);
}
else {
//qDebug(logGui()) << "Spot:" << spot.value()->dxcall << "Timestamp" << spot.value()->timestamp.addSecs(timeout * 60) << "not lower than" << time;
QElapsedTimer timer;
timer.start();
QMap<QString, spotData*>::iterator spot1 = clusterSpots.begin();
while (spot1 != clusterSpots.end()) {
spot1.value()->current = false;
++spot1;
}
foreach(spotData s, spots)
{
bool found = false;
QMap<QString, spotData*>::iterator spot = clusterSpots.find(s.dxcall);
while (spot != clusterSpots.end() && spot.key() == s.dxcall && spot.value()->frequency == s.frequency) {
spot.value()->current = true;
found = true;
++spot;
}
if (!found)
{
spotData* sp = new spotData();
sp->dxcall = s.dxcall;
sp->frequency = s.frequency;
//qDebug(logCluster()) << "ADD:" << sp->dxcall;
sp->current = true;
bool conflict = true;
double left = sp->frequency;
double top = rigCaps.spectAmpMax - 10;
sp->text = new QCPItemText(plot);
sp->text->setAntialiased(true);
sp->text->setColor(QColor(Qt::red));
sp->text->setText(sp->dxcall);
sp->text->setFont(QFont(font().family(), 10));
sp->text->setPositionAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
sp->text->position->setType(QCPItemPosition::ptPlotCoords);
sp->text->setSelectable(true);
QMargins margin;
int width = (sp->text->right - sp->text->left) / 2;
margin.setLeft(width);
margin.setRight(width);
sp->text->setPadding(margin);
sp->text->position->setCoords(left, top);
sp->text->setVisible(false);
while (conflict) {
QCPItemText* textItem = plot->itemAt<QCPItemText>(sp->text->position->pixelPosition(), true);
if (textItem != nullptr && sp->text != textItem) {
//qInfo(logGui()) << "CONFLICT:" << textItem->text() << "SAME POSITION AS" << sp->dxcall << sp->text->position->pixelPosition();
top = top - 5.0;
}
else {
//qInfo(logGui()) << "OK:" << sp->dxcall << sp->text->position->pixelPosition();
conflict = false;
}
sp->text->position->setCoords(left, top);
}
sp->text->setVisible(true);
clusterSpots.insert(sp->dxcall, sp);
}
}
}
QMap<QString, spotData*>::iterator spot2 = clusterSpots.begin();
while (spot2 != clusterSpots.end()) {
if (spot2.value()->current == false) {
plot->removeItem(spot2.value()->text);
//qDebug(logCluster()) << "REMOVE:" << spot2.value()->dxcall;
delete spot2.value(); // Stop memory leak?
spot2 = clusterSpots.erase(spot2);
}
else {
++spot2;
}
}
//qDebug(logCluster()) << "Processing took" << timer.nsecsElapsed() / 1000 << "us";
}

Wyświetl plik

@ -18,6 +18,8 @@
#include <QMutexLocker>
#include <QColorDialog>
#include <QColor>
#include <QSqlDatabase>
#include <QSqlQuery>
#include "logcategories.h"
#include "commhandler.h"
@ -40,6 +42,7 @@
#include "colorprefs.h"
#include "loggingwindow.h"
#include "cluster.h"
#include "database.h"
#include <qcustomplot.h>
#include <qserialportinfo.h>
@ -197,11 +200,9 @@ signals:
void setClusterUserName(QString name);
void setClusterPassword(QString pass);
void setClusterTimeout(int timeout);
void setFrequencyRange(double low, double high);
private slots:
void addClusterSpot(spotData* spot);
void deleteClusterSpot(QString dxcall);
void deleteOldClusterSpots(int timeout);
void updateSizes(int tabIndex);
void shortcutF1();
void shortcutF2();
@ -675,7 +676,7 @@ private slots:
void on_clusterTimeoutLineEdit_editingFinished();
void receiveClusterOutput(QString text);
void receiveSpots(QList<spotData> spots);
private:
Ui::wfmain *ui;
@ -1078,6 +1079,7 @@ private:
QCPItemText* text=Q_NULLPTR;
QList<clusterSettings> clusters;
QMutex clusterMutex;
QSqlDatabase db;
};
Q_DECLARE_METATYPE(struct rigCapabilities)
@ -1097,6 +1099,7 @@ Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode)
Q_DECLARE_METATYPE(enum mode_kind)
Q_DECLARE_METATYPE(QList<radio_cap_packet>)
Q_DECLARE_METATYPE(QList<spotData>)
Q_DECLARE_METATYPE(rigstate*)
//void (*wfmain::logthistext)(QString text) = NULL;

0
wfview 100644
Wyświetl plik

Wyświetl plik

@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui serialport network multimedia xml
QT += core gui serialport network multimedia xml sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
@ -175,6 +175,7 @@ SOURCES += main.cpp\
selectradio.cpp \
tcpserver.cpp \
cluster.cpp \
database.cpp \
aboutbox.cpp
HEADERS += wfmain.h \
@ -212,6 +213,7 @@ HEADERS += wfmain.h \
selectradio.h \
tcpserver.h \
cluster.h \
database.h \
aboutbox.h