mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-24 19:00:36 -05:00
223 lines
6.8 KiB
C++
223 lines
6.8 KiB
C++
///////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
|
|
// //
|
|
// This program is free software; you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation as version 3 of the License, or //
|
|
// (at your option) any later version. //
|
|
// //
|
|
// This program is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU General Public License V3 for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <QtWebSockets>
|
|
#include <QHostAddress>
|
|
#include <QDebug>
|
|
|
|
#include "util/timeutil.h"
|
|
#include "wsspectrum.h"
|
|
|
|
WSSpectrum::WSSpectrum(QObject *parent) :
|
|
QObject(parent),
|
|
m_listeningAddress(QHostAddress::LocalHost),
|
|
m_port(8887),
|
|
m_webSocketServer(nullptr)
|
|
{
|
|
connect(this,
|
|
SIGNAL(payloadToSend(const QByteArray&)),
|
|
this,
|
|
SLOT(sendPayload(const QByteArray&)),
|
|
Qt::QueuedConnection);
|
|
m_timer.start();
|
|
}
|
|
|
|
WSSpectrum::~WSSpectrum()
|
|
{
|
|
disconnect(this,
|
|
SIGNAL(payloadToSend(const QByteArray&)),
|
|
this,
|
|
SLOT(sendPayload(const QByteArray&)));
|
|
closeSocket();
|
|
}
|
|
|
|
void WSSpectrum::openSocket()
|
|
{
|
|
m_webSocketServer = new QWebSocketServer(
|
|
QStringLiteral("Spectrum Server"),
|
|
QWebSocketServer::NonSecureMode,
|
|
this);
|
|
|
|
if (m_webSocketServer->listen(m_listeningAddress, m_port))
|
|
{
|
|
qDebug() << "WSSpectrum::openSocket: spectrum server listening at " << m_listeningAddress.toString() << " on port " << m_port;
|
|
connect(m_webSocketServer, &QWebSocketServer::newConnection, this, &WSSpectrum::onNewConnection);
|
|
}
|
|
else
|
|
{
|
|
qInfo("WSSpectrum::openSocket: cannot start spectrum server at %s on port %u", qPrintable(m_listeningAddress.toString()), m_port);
|
|
}
|
|
}
|
|
|
|
void WSSpectrum::closeSocket()
|
|
{
|
|
if (m_webSocketServer)
|
|
{
|
|
qDebug() << "WSSpectrum::closeSocket: stopping spectrum server listening at " << m_listeningAddress.toString() << " on port " << m_port;
|
|
delete m_webSocketServer;
|
|
m_webSocketServer = nullptr;
|
|
}
|
|
}
|
|
|
|
bool WSSpectrum::socketOpened() const
|
|
{
|
|
return m_webSocketServer && m_webSocketServer->isListening();
|
|
}
|
|
|
|
void WSSpectrum::getPeers(QList<QHostAddress>& hosts, QList<quint16>& ports) const
|
|
{
|
|
hosts.clear();
|
|
ports.clear();
|
|
|
|
for (auto pSocket : m_clients)
|
|
{
|
|
hosts.push_back(pSocket->peerAddress());
|
|
ports.push_back(pSocket->peerPort());
|
|
}
|
|
}
|
|
|
|
void WSSpectrum::setListeningAddress(const QString& address)
|
|
{
|
|
if (address == "127.0.0.1") {
|
|
m_listeningAddress.setAddress(QHostAddress::LocalHost);
|
|
} else if (address == "0.0.0.0") {
|
|
m_listeningAddress.setAddress(QHostAddress::Any);
|
|
} else {
|
|
m_listeningAddress.setAddress(address);
|
|
}
|
|
}
|
|
|
|
QString WSSpectrum::getWebSocketIdentifier(QWebSocket *peer)
|
|
{
|
|
return QStringLiteral("%1:%2").arg(peer->peerAddress().toString(), QString::number(peer->peerPort()));
|
|
}
|
|
|
|
void WSSpectrum::onNewConnection()
|
|
{
|
|
auto pSocket = m_webSocketServer->nextPendingConnection();
|
|
qDebug() << "WSSpectrum::onNewConnection: " << getWebSocketIdentifier(pSocket) << " connected";
|
|
pSocket->setParent(this);
|
|
|
|
connect(pSocket, &QWebSocket::textMessageReceived, this, &WSSpectrum::processClientMessage);
|
|
connect(pSocket, &QWebSocket::disconnected, this, &WSSpectrum::socketDisconnected);
|
|
|
|
m_clients << pSocket;
|
|
}
|
|
|
|
void WSSpectrum::processClientMessage(const QString &message)
|
|
{
|
|
qDebug() << "WSSpectrum::processClientMessage: " << message;
|
|
}
|
|
|
|
void WSSpectrum::socketDisconnected()
|
|
{
|
|
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
|
|
qDebug() << getWebSocketIdentifier(pClient) << " disconnected";
|
|
|
|
if (pClient)
|
|
{
|
|
m_clients.removeAll(pClient);
|
|
pClient->deleteLater();
|
|
}
|
|
}
|
|
|
|
QHostAddress WSSpectrum::getListeningAddress() const
|
|
{
|
|
if (m_webSocketServer) {
|
|
return m_webSocketServer->serverAddress();
|
|
} else {
|
|
return QHostAddress::Null;
|
|
}
|
|
}
|
|
|
|
uint16_t WSSpectrum::getListeningPort() const
|
|
{
|
|
if (m_webSocketServer) {
|
|
return m_webSocketServer->serverPort();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void WSSpectrum::newSpectrum(
|
|
const std::vector<Real>& spectrum,
|
|
int fftSize,
|
|
uint64_t centerFrequency,
|
|
int bandwidth,
|
|
bool linear,
|
|
bool ssb,
|
|
bool usb
|
|
)
|
|
{
|
|
if (m_timer.elapsed() < 200) { // Max 5 frames per second
|
|
return;
|
|
}
|
|
|
|
qint64 elapsed = m_timer.restart();
|
|
uint64_t nowMs = TimeUtil::nowms();
|
|
QByteArray payload;
|
|
|
|
buildPayload(
|
|
payload,
|
|
spectrum,
|
|
fftSize,
|
|
elapsed,
|
|
nowMs,
|
|
centerFrequency,
|
|
bandwidth,
|
|
linear,
|
|
ssb,
|
|
usb
|
|
);
|
|
//qDebug() << "WSSpectrum::newSpectrum: " << payload.size() << " bytes in " << elapsed << " ms";
|
|
emit payloadToSend(payload);
|
|
}
|
|
|
|
void WSSpectrum::sendPayload(const QByteArray& payload)
|
|
{
|
|
//qDebug() << "WSSpectrum::sendPayload: " << payload.size() << " bytes";
|
|
for (QWebSocket *pClient : qAsConst(m_clients)) {
|
|
pClient->sendBinaryMessage(payload);
|
|
}
|
|
}
|
|
|
|
void WSSpectrum::buildPayload(
|
|
QByteArray& bytes,
|
|
const std::vector<Real>& spectrum,
|
|
int fftSize,
|
|
int64_t fftTimeMs,
|
|
uint64_t timestampMs,
|
|
uint64_t centerFrequency,
|
|
int bandwidth,
|
|
bool linear,
|
|
bool ssb,
|
|
bool usb
|
|
)
|
|
{
|
|
QBuffer buffer(&bytes);
|
|
buffer.open(QIODevice::WriteOnly);
|
|
buffer.write((char*) ¢erFrequency, sizeof(uint64_t)); // 0
|
|
buffer.write((char*) &fftTimeMs, sizeof(int64_t)); // 8
|
|
buffer.write((char*) ×tampMs, sizeof(uint64_t)); // 16
|
|
buffer.write((char*) &fftSize, sizeof(int)); // 24
|
|
buffer.write((char*) &bandwidth, sizeof(int)); // 28
|
|
int indicators = (linear ? 1 : 0) + (ssb ? 2 : 0) + (usb ? 4 : 0);
|
|
buffer.write((char*) &indicators, sizeof(int)); // 32
|
|
buffer.write((char*) spectrum.data(), fftSize*sizeof(Real)); // 36
|
|
buffer.close();
|
|
}
|