mirror of
https://github.com/JvanKatwijk/dab-cmdline
synced 2025-10-05 23:52:50 +02:00
364 lines
11 KiB
C++
364 lines
11 KiB
C++
#
|
|
/*
|
|
* Copyright (C) 2010, 2011, 2012
|
|
* Jan van Katwijk (J.vanKatwijk@gmail.com)
|
|
* Lazy Chair Computing
|
|
*
|
|
* This file is part of the SDR-J.
|
|
* Many of the ideas as implemented in SDR-J are derived from
|
|
* other work, made available through the GNU general Public License.
|
|
* All copyrights of the original authors are recognized.
|
|
*
|
|
* SDR-J 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* SDR-J 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 for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with SDR-J; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* A simple client for rtl_tcp
|
|
*/
|
|
|
|
#include <QSettings>
|
|
#include <QLabel>
|
|
#include <QMessageBox>
|
|
#include <QHostAddress>
|
|
#include <QTcpSocket>
|
|
#include "rtl_tcp_client.h"
|
|
//
|
|
#define DEFAULT_FREQUENCY (Khz (220000))
|
|
|
|
rtl_tcp_client::rtl_tcp_client (QSettings *s,
|
|
bool *success, bool visible) {
|
|
remoteSettings = s;
|
|
*success = false;
|
|
|
|
theFrame = new QFrame;
|
|
setupUi (theFrame);
|
|
if (visible)
|
|
this -> theFrame -> show ();
|
|
|
|
// setting the defaults and constants
|
|
theRate = 2048000;
|
|
remoteSettings -> beginGroup ("rtl_tcp_client");
|
|
theGain = remoteSettings ->
|
|
value ("rtl_tcp_client-gain", 20). toInt ();
|
|
thePpm = remoteSettings ->
|
|
value ("rtl_tcp_client-ppm", 0). toInt ();
|
|
vfoOffset = remoteSettings ->
|
|
value ("rtl_tcp_client-offset", 0). toInt ();
|
|
basePort = remoteSettings ->
|
|
value ("rtl_tcp_port", 1234).toInt();
|
|
remoteSettings -> endGroup ();
|
|
tcp_gain -> setValue (theGain);
|
|
tcp_ppm -> setValue (thePpm);
|
|
vfoFrequency = DEFAULT_FREQUENCY;
|
|
theBuffer = new RingBuffer<uint8_t>(32 * 32768);
|
|
#ifdef GUI_3
|
|
theShadowBuffer = new RingBuffer<uint8_t>(8192);
|
|
#endif
|
|
connected = false;
|
|
hostLineEdit = new QLineEdit (NULL);
|
|
|
|
if (visible) {
|
|
connect (tcp_connect, SIGNAL (clicked (void)),
|
|
this, SLOT (wantConnect (void)));
|
|
connect (tcp_disconnect, SIGNAL (clicked (void)),
|
|
this, SLOT (setDisconnect (void)));
|
|
connect (tcp_gain, SIGNAL (valueChanged (int)),
|
|
this, SLOT (sendGain (int)));
|
|
connect (tcp_ppm, SIGNAL (valueChanged (int)),
|
|
this, SLOT (set_fCorrection (int)));
|
|
connect (khzOffset, SIGNAL (valueChanged (int)),
|
|
this, SLOT (set_Offset (int)));
|
|
state -> setText ("waiting to start");
|
|
*success = true;
|
|
return;
|
|
}
|
|
//
|
|
// If we do not make the widget visible, we assume there is an
|
|
// ipAddress in the remoteSettings, and we connect (try to connect)
|
|
// to that
|
|
|
|
remoteSettings -> beginGroup ("rtl_tcp_client");
|
|
QString ipAddress = remoteSettings ->
|
|
value ("rtl_tcp_address", "127.0.0.1"). toString ();
|
|
remoteSettings -> endGroup ();
|
|
serverAddress = QHostAddress (ipAddress);
|
|
toServer. connectToHost (serverAddress, basePort);
|
|
if (!toServer. waitForConnected (2000)) {
|
|
*success = false;
|
|
return;
|
|
}
|
|
|
|
setAgc (true);
|
|
sendRate (theRate);
|
|
sendVFO (DEFAULT_FREQUENCY);
|
|
toServer. waitForBytesWritten ();
|
|
connected = true;
|
|
*success = true;
|
|
}
|
|
|
|
rtl_tcp_client::~rtl_tcp_client (void) {
|
|
remoteSettings -> beginGroup ("rtl_tcp_client");
|
|
if (connected) { // close previous connection
|
|
stopReader ();
|
|
// streamer. close ();
|
|
remoteSettings -> setValue ("remote-server",
|
|
toServer. peerAddress (). toString ());
|
|
QByteArray datagram;
|
|
}
|
|
remoteSettings -> setValue ("rtl_tcp_client-gain", theGain);
|
|
remoteSettings -> setValue ("rtl_tcp_client-ppm", thePpm);
|
|
remoteSettings -> setValue ("rtl_tcp_client-offset", vfoOffset);
|
|
remoteSettings -> endGroup ();
|
|
toServer. close ();
|
|
delete theBuffer;
|
|
#ifdef GUI_3
|
|
delete theShadowBuffer;
|
|
#endif
|
|
delete hostLineEdit;
|
|
delete theFrame;
|
|
}
|
|
//
|
|
void rtl_tcp_client::wantConnect (void) {
|
|
QString ipAddress;
|
|
int16_t i;
|
|
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
|
|
|
|
if (connected)
|
|
return;
|
|
// use the first non-localhost IPv4 address
|
|
for (i = 0; i < ipAddressesList.size(); ++i) {
|
|
if (ipAddressesList.at (i) != QHostAddress::LocalHost &&
|
|
ipAddressesList. at (i). toIPv4Address ()) {
|
|
ipAddress = ipAddressesList. at(i). toString();
|
|
break;
|
|
}
|
|
}
|
|
// if we did not find one, use IPv4 localhost
|
|
if (ipAddress. isEmpty())
|
|
ipAddress = QHostAddress (QHostAddress::LocalHost).toString ();
|
|
remoteSettings -> beginGroup ("rtl_tcp_client");
|
|
ipAddress = remoteSettings ->
|
|
value ("remote-server", ipAddress). toString ();
|
|
remoteSettings -> endGroup ();
|
|
hostLineEdit -> setText (ipAddress);
|
|
|
|
hostLineEdit -> setInputMask ("000.000.000.000");
|
|
// Setting default IP address
|
|
hostLineEdit -> show ();
|
|
state -> setText ("Give IP address, return");
|
|
connect (hostLineEdit, SIGNAL (returnPressed (void)),
|
|
this, SLOT (setConnection (void)));
|
|
}
|
|
|
|
// if/when a return is pressed in the line edit,
|
|
// a signal appears and we are able to collect the
|
|
// inserted text. The format is the IP-V4 format.
|
|
// Using this text, we try to connect,
|
|
void rtl_tcp_client::setConnection (void) {
|
|
QString s = hostLineEdit -> text ();
|
|
QHostAddress theAddress = QHostAddress (s);
|
|
|
|
serverAddress = QHostAddress (s);
|
|
disconnect (hostLineEdit, SIGNAL (returnPressed (void)),
|
|
this, SLOT (setConnection (void)));
|
|
toServer. connectToHost (serverAddress, basePort);
|
|
if (!toServer. waitForConnected (2000)) {
|
|
QMessageBox::warning (theFrame, tr ("sdr"),
|
|
tr ("connection failed\n"));
|
|
return;
|
|
}
|
|
|
|
sendGain (theGain);
|
|
sendRate (theRate);
|
|
sendVFO (DEFAULT_FREQUENCY - theRate / 4);
|
|
toServer. waitForBytesWritten ();
|
|
state -> setText ("Connected");
|
|
connected = true;
|
|
}
|
|
|
|
int32_t rtl_tcp_client::getRate (void) {
|
|
return theRate;
|
|
}
|
|
|
|
bool rtl_tcp_client::legalFrequency (int32_t f) {
|
|
(void)f;
|
|
return true;
|
|
}
|
|
|
|
int32_t rtl_tcp_client::defaultFrequency (void) {
|
|
return DEFAULT_FREQUENCY; // choose any legal frequency here
|
|
}
|
|
|
|
void rtl_tcp_client::setVFOFrequency (int32_t newFrequency) {
|
|
if (!connected)
|
|
return;
|
|
vfoFrequency = newFrequency;
|
|
// here the command to set the frequency
|
|
sendVFO (newFrequency);
|
|
}
|
|
|
|
int32_t rtl_tcp_client::getVFOFrequency (void) {
|
|
return vfoFrequency;
|
|
}
|
|
|
|
bool rtl_tcp_client::restartReader (void) {
|
|
if (!connected)
|
|
return false;
|
|
connect (&toServer, SIGNAL (readyRead (void)),
|
|
this, SLOT (readData (void)));
|
|
return true;
|
|
}
|
|
|
|
void rtl_tcp_client::stopReader (void) {
|
|
if (connected)
|
|
disconnect (&toServer, SIGNAL (readyRead (void)),
|
|
this, SLOT (readData (void)));
|
|
}
|
|
//
|
|
//
|
|
// The brave old getSamples. For the dab stick, we get
|
|
// size: still in I/Q pairs, but we have to convert the data from
|
|
// uint8_t to DSPCOMPLEX *
|
|
int32_t rtl_tcp_client::getSamples (DSPCOMPLEX *V, int32_t size) {
|
|
int32_t amount, i;
|
|
uint8_t *tempBuffer = (uint8_t *)alloca (2 * size * sizeof (uint8_t));
|
|
//
|
|
amount = theBuffer -> getDataFromBuffer (tempBuffer, 2 * size);
|
|
for (i = 0; i < amount / 2; i ++)
|
|
V [i] = DSPCOMPLEX ((float (tempBuffer [2 * i] - 128)) / 128.0,
|
|
(float (tempBuffer [2 * i + 1] - 128)) / 128.0);
|
|
return amount / 2;
|
|
}
|
|
|
|
#ifdef GUI_3
|
|
int32_t rtl_tcp_client::getSamplesFromShadowBuffer (DSPCOMPLEX *V,
|
|
int32_t size) {
|
|
int32_t amount, i;
|
|
uint8_t *tempBuffer = (uint8_t *)alloca (2 * size * sizeof (uint8_t));
|
|
//
|
|
amount = theShadowBuffer -> getDataFromBuffer(tempBuffer, 2 * size);
|
|
for (i = 0; i < amount / 2; i ++)
|
|
V [i] = DSPCOMPLEX ((float (tempBuffer [2 * i] - 128)) / 128.0,
|
|
(float (tempBuffer [2 * i + 1] - 128)) / 128.0);
|
|
return amount / 2;
|
|
}
|
|
#endif
|
|
|
|
int32_t rtl_tcp_client::Samples (void) {
|
|
return theBuffer -> GetRingBufferReadAvailable () / 2;
|
|
}
|
|
//
|
|
uint8_t rtl_tcp_client::myIdentity (void) {
|
|
return DAB_STICK;
|
|
}
|
|
|
|
//
|
|
// bitDepth is required in the forthcoming 6.1 release
|
|
// In 6.0 it is not called
|
|
// It is used to set the scale for the spectrum
|
|
int16_t rtl_tcp_client::bitDepth (void) {
|
|
return 8;
|
|
}
|
|
|
|
// These functions are typical for network use
|
|
void rtl_tcp_client::readData (void) {
|
|
uint8_t buffer [8192];
|
|
while (toServer. bytesAvailable () > 8192) {
|
|
toServer. read ((char *)buffer, 8192);
|
|
theBuffer -> putDataIntoBuffer (buffer, 8192);
|
|
#ifdef GUI_3
|
|
theShadowBuffer -> putDataIntoBuffer (buffer, 8192);
|
|
#endif
|
|
}
|
|
}
|
|
//
|
|
//
|
|
// commands are packed in 5 bytes, one "command byte"
|
|
// and an integer parameter
|
|
struct command {
|
|
unsigned char cmd;
|
|
unsigned int param;
|
|
}__attribute__((packed));
|
|
|
|
#define ONE_BYTE 8
|
|
|
|
void rtl_tcp_client::sendCommand (uint8_t cmd, int32_t param) {
|
|
QByteArray datagram;
|
|
|
|
datagram. resize (5);
|
|
datagram [0] = cmd; // command to set rate
|
|
datagram [4] = param & 0xFF; //lsb last
|
|
datagram [3] = (param >> ONE_BYTE) & 0xFF;
|
|
datagram [2] = (param >> (2 * ONE_BYTE)) & 0xFF;
|
|
datagram [1] = (param >> (3 * ONE_BYTE)) & 0xFF;
|
|
toServer. write (datagram. data (), datagram. size ());
|
|
}
|
|
|
|
void rtl_tcp_client::sendVFO (int32_t frequency) {
|
|
sendCommand (0x01, frequency);
|
|
}
|
|
|
|
void rtl_tcp_client::sendRate (int32_t theRate) {
|
|
sendCommand (0x02, theRate);
|
|
}
|
|
|
|
void rtl_tcp_client::setGainMode (int32_t gainMode) {
|
|
sendCommand (0x03, gainMode);
|
|
}
|
|
|
|
void rtl_tcp_client::sendGain (int gain) {
|
|
sendCommand (0x04, 10 * gain);
|
|
theGain = gain;
|
|
}
|
|
|
|
//
|
|
// the "setGain" function is to accomodate gui_3.
|
|
void rtl_tcp_client::setGain (int32_t g) {
|
|
sendGain (g);
|
|
}
|
|
|
|
void rtl_tcp_client::setAgc (bool b) {
|
|
if (b)
|
|
setGainMode(0);
|
|
else
|
|
setGainMode(1);
|
|
}
|
|
|
|
// correction is in ppm
|
|
void rtl_tcp_client::set_fCorrection (int32_t ppm) {
|
|
sendCommand (0x05, ppm);
|
|
thePpm = ppm;
|
|
}
|
|
|
|
void rtl_tcp_client::setDisconnect (void) {
|
|
if (connected) { // close previous connection
|
|
stopReader ();
|
|
remoteSettings -> beginGroup ("rtl_tcp_client");
|
|
remoteSettings -> setValue ("remote-server",
|
|
toServer. peerAddress (). toString ());
|
|
remoteSettings -> setValue ("rtl_tcp_client-gain", theGain);
|
|
remoteSettings -> setValue ("rtl_tcp_client-ppm", thePpm);
|
|
remoteSettings -> endGroup ();
|
|
toServer. close ();
|
|
}
|
|
connected = false;
|
|
connectedLabel -> setText (" ");
|
|
state -> setText ("disconnected");
|
|
}
|
|
|
|
void rtl_tcp_client::set_Offset (int32_t o) {
|
|
sendCommand (0x0a, Khz (o));
|
|
vfoOffset = o;
|
|
}
|
|
|