2018-05-15 21:57:28 +02:00
|
|
|
#
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 .. 2017
|
|
|
|
* Jan van Katwijk (J.vanKatwijk@gmail.com)
|
|
|
|
* Lazy Chair Computing
|
|
|
|
*
|
|
|
|
* This file is part of Qt-DAB
|
|
|
|
*
|
|
|
|
* Qt-DAB 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 version 2 of the License.
|
|
|
|
*
|
|
|
|
* Qt-DAB 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 Qt-DAB if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QThread>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <QLabel>
|
|
|
|
#include "hackrf-handler.h"
|
|
|
|
|
|
|
|
#define DEFAULT_GAIN 30
|
|
|
|
|
|
|
|
hackrfHandler::hackrfHandler (QSettings *s) {
|
|
|
|
int err;
|
|
|
|
int res;
|
|
|
|
hackrfSettings = s;
|
|
|
|
this -> myFrame = new QFrame (NULL);
|
|
|
|
setupUi (this -> myFrame);
|
|
|
|
this -> myFrame -> show ();
|
|
|
|
this -> inputRate = Khz (2048);
|
2018-05-17 10:48:38 +02:00
|
|
|
_I_Buffer = NULL;
|
|
|
|
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
const char *libraryString = "hackrf.dll";
|
|
|
|
Handle = LoadLibrary ((wchar_t *)L"hackrf.dll");
|
|
|
|
#else
|
|
|
|
const char *libraryString = "libhackrf.so";
|
|
|
|
Handle = dlopen (libraryString, RTLD_NOW);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (Handle == NULL) {
|
|
|
|
fprintf (stderr, "failed to open %s\n", libraryString);
|
|
|
|
delete myFrame;
|
|
|
|
throw (20);
|
|
|
|
}
|
|
|
|
|
|
|
|
libraryLoaded = true;
|
|
|
|
if (!load_hackrfFunctions ()) {
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
FreeLibrary (Handle);
|
|
|
|
#else
|
|
|
|
dlclose (Handle);
|
|
|
|
#endif
|
|
|
|
delete myFrame;
|
|
|
|
throw (21);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// From here we have a library available
|
|
|
|
|
2018-05-15 21:57:28 +02:00
|
|
|
_I_Buffer = new RingBuffer<std::complex<float>>(1024 * 1024);
|
|
|
|
vfoFrequency = Khz (220000);
|
|
|
|
//
|
|
|
|
// See if there are settings from previous incarnations
|
|
|
|
hackrfSettings -> beginGroup ("hackrfSettings");
|
|
|
|
lnagainSlider -> setValue (
|
|
|
|
hackrfSettings -> value ("hack_lnaGain", DEFAULT_GAIN). toInt ());
|
|
|
|
vgagainSlider -> setValue (
|
|
|
|
hackrfSettings -> value ("hack_vgaGain", DEFAULT_GAIN). toInt ());
|
|
|
|
|
|
|
|
hackrfSettings -> endGroup ();
|
|
|
|
|
|
|
|
//
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_init ();
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_init:");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
delete myFrame;
|
|
|
|
throw (21);
|
|
|
|
}
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_open (&theDevice);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_open:");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
delete myFrame;
|
|
|
|
throw (22);
|
|
|
|
}
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_set_sample_rate (theDevice, 2048000.0);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_set_samplerate:");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
delete myFrame;
|
|
|
|
throw (23);
|
|
|
|
}
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_set_baseband_filter_bandwidth (theDevice,
|
2018-05-19 15:51:34 +02:00
|
|
|
1750000);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_set_bw:");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
delete myFrame;
|
|
|
|
throw (24);
|
|
|
|
}
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_set_freq (theDevice, 220000000);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_set_freq: ");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
delete myFrame;
|
|
|
|
throw (25);
|
|
|
|
}
|
|
|
|
|
|
|
|
setLNAGain (lnagainSlider -> value ());
|
|
|
|
setVGAGain (vgagainSlider -> value ());
|
|
|
|
// and be prepared for future changes in the settings
|
|
|
|
connect (lnagainSlider, SIGNAL (valueChanged (int)),
|
|
|
|
this, SLOT (setLNAGain (int)));
|
|
|
|
connect (vgagainSlider, SIGNAL (valueChanged (int)),
|
|
|
|
this, SLOT (setVGAGain (int)));
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
hackrf_device_list_t *deviceList = this -> hackrf_device_list ();
|
2018-05-19 15:51:34 +02:00
|
|
|
if (deviceList != NULL) { // well, it should be
|
2018-05-17 10:48:38 +02:00
|
|
|
char *serial = deviceList -> serial_numbers [0];
|
|
|
|
serial_number_display -> setText (serial);
|
|
|
|
enum hackrf_usb_board_id board_id =
|
|
|
|
deviceList -> usb_board_ids [0];
|
|
|
|
usb_board_id_display ->
|
|
|
|
setText (this -> hackrf_usb_board_id_name (board_id));
|
|
|
|
}
|
|
|
|
|
2018-05-15 21:57:28 +02:00
|
|
|
running. store (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
hackrfHandler::~hackrfHandler (void) {
|
|
|
|
stopReader ();
|
|
|
|
delete myFrame;
|
|
|
|
if (_I_Buffer != NULL)
|
|
|
|
delete _I_Buffer;
|
2018-05-17 10:48:38 +02:00
|
|
|
hackrfSettings -> beginGroup ("hackrfSettings");
|
|
|
|
hackrfSettings -> setValue ("hack_lnaGain",
|
|
|
|
lnagainSlider -> value ());
|
|
|
|
hackrfSettings -> setValue ("hack_vgaGain",
|
|
|
|
vgagainSlider -> value ());
|
|
|
|
hackrfSettings -> endGroup ();
|
|
|
|
this -> hackrf_close (theDevice);
|
|
|
|
this -> hackrf_exit ();
|
2018-05-15 21:57:28 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
|
|
|
|
void hackrfHandler::setVFOFrequency (int32_t newFrequency) {
|
|
|
|
int res;
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_set_freq (theDevice, newFrequency);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_set_freq: \n");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
vfoFrequency = newFrequency;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t hackrfHandler::getVFOFrequency (void) {
|
|
|
|
return vfoFrequency;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hackrfHandler::setLNAGain (int newGain) {
|
|
|
|
int res;
|
2018-05-17 10:48:38 +02:00
|
|
|
if ((newGain <= 40) && (newGain >= 0)) {
|
|
|
|
res = this -> hackrf_set_lna_gain (theDevice, newGain);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_lna_gain :\n");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
lnagainDisplay -> display (newGain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void hackrfHandler::setVGAGain (int newGain) {
|
|
|
|
int res;
|
|
|
|
if ((newGain <= 62) && (newGain >= 0)) {
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_set_vga_gain (theDevice, newGain);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_vga_gain :\n");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
vgagainDisplay -> display (newGain);
|
|
|
|
}
|
|
|
|
}
|
2018-05-17 10:48:38 +02:00
|
|
|
//
|
|
|
|
// we use a static large buffer, rather than trying to allocate
|
|
|
|
// a buffer on the stack
|
2018-05-15 21:57:28 +02:00
|
|
|
static std::complex<float>buffer [32 * 32768];
|
|
|
|
static
|
|
|
|
int callback (hackrf_transfer *transfer) {
|
|
|
|
hackrfHandler *ctx = static_cast <hackrfHandler *>(transfer -> rx_ctx);
|
|
|
|
int i;
|
|
|
|
uint8_t *p = transfer -> buffer;
|
|
|
|
RingBuffer<std::complex<float> > * q = ctx -> _I_Buffer;
|
|
|
|
|
|
|
|
for (i = 0; i < transfer -> valid_length / 2; i ++) {
|
2018-05-17 10:48:38 +02:00
|
|
|
float re = (int8_t)(p [2 * i]) / 128.0;
|
|
|
|
float im = (int8_t)(p [2 * i + 1]) / 128.0;
|
2018-05-15 21:57:28 +02:00
|
|
|
buffer [i] = std::complex<float> (re, im);
|
|
|
|
}
|
|
|
|
q -> putDataIntoBuffer (buffer, transfer -> valid_length / 2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hackrfHandler::restartReader (void) {
|
|
|
|
int res;
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
if (running. load ())
|
|
|
|
return true;
|
2018-05-15 21:57:28 +02:00
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_start_rx (theDevice, callback, this);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_start_rx :\n");
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-05-17 10:48:38 +02:00
|
|
|
running. store (this -> hackrf_is_streaming (theDevice));
|
2018-05-15 21:57:28 +02:00
|
|
|
return running. load ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void hackrfHandler::stopReader (void) {
|
|
|
|
int res;
|
|
|
|
|
|
|
|
if (!running. load ())
|
|
|
|
return;
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
res = this -> hackrf_stop_rx (theDevice);
|
2018-05-15 21:57:28 +02:00
|
|
|
if (res != HACKRF_SUCCESS) {
|
2018-05-17 10:48:38 +02:00
|
|
|
fprintf (stderr, "Problem with hackrf_stop_rx :\n", res);
|
|
|
|
fprintf (stderr, "%s \n",
|
|
|
|
this -> hackrf_error_name (hackrf_error (res)));
|
2018-05-15 21:57:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
running. store (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// The brave old getSamples. For the hackrf, we get
|
|
|
|
// size still in I/Q pairs
|
|
|
|
int32_t hackrfHandler::getSamples (std::complex<float> *V, int32_t size) {
|
|
|
|
return _I_Buffer -> getDataFromBuffer (V, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t hackrfHandler::Samples (void) {
|
|
|
|
return _I_Buffer -> GetRingBufferReadAvailable ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void hackrfHandler::resetBuffer (void) {
|
|
|
|
_I_Buffer -> FlushRingBuffer ();
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t hackrfHandler::bitDepth (void) {
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
bool hackrfHandler::load_hackrfFunctions (void) {
|
|
|
|
//
|
|
|
|
// link the required procedures
|
|
|
|
this -> hackrf_init = (pfn_hackrf_init)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_init");
|
|
|
|
if (this -> hackrf_init == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_init\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_open = (pfn_hackrf_open)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_open");
|
|
|
|
if (this -> hackrf_open == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_open\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_close = (pfn_hackrf_close)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_close");
|
|
|
|
if (this -> hackrf_close == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_close\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_exit = (pfn_hackrf_exit)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_exit");
|
|
|
|
if (this -> hackrf_exit == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_exit\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_start_rx = (pfn_hackrf_start_rx)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_start_rx");
|
|
|
|
if (this -> hackrf_start_rx == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_start_rx\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_stop_rx = (pfn_hackrf_stop_rx)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_stop_rx");
|
|
|
|
if (this -> hackrf_stop_rx == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_stop_rx\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_device_list = (pfn_hackrf_device_list)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_device_list");
|
|
|
|
if (this -> hackrf_device_list == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_device_list\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_set_baseband_filter_bandwidth =
|
|
|
|
(pfn_hackrf_set_baseband_filter_bandwidth)
|
|
|
|
GETPROCADDRESS (Handle,
|
|
|
|
"hackrf_set_baseband_filter_bandwidth");
|
|
|
|
if (this -> hackrf_set_baseband_filter_bandwidth == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_set_baseband_filter_bandwidth\n");
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-15 21:57:28 +02:00
|
|
|
|
2018-05-17 10:48:38 +02:00
|
|
|
this -> hackrf_set_lna_gain = (pfn_hackrf_set_lna_gain)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_set_lna_gain");
|
|
|
|
if (this -> hackrf_set_lna_gain == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_set_lna_gain\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_set_vga_gain = (pfn_hackrf_set_vga_gain)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_set_vga_gain");
|
|
|
|
if (this -> hackrf_set_vga_gain == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_set_vga_gain\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_set_freq = (pfn_hackrf_set_freq)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_set_freq");
|
|
|
|
if (this -> hackrf_set_freq == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_set_freq\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_set_sample_rate = (pfn_hackrf_set_sample_rate)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_set_sample_rate");
|
|
|
|
if (this -> hackrf_set_sample_rate == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_set_sample_rate\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_is_streaming = (pfn_hackrf_is_streaming)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_is_streaming");
|
|
|
|
if (this -> hackrf_is_streaming == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_is_streaming\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_error_name = (pfn_hackrf_error_name)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_error_name");
|
|
|
|
if (this -> hackrf_error_name == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_error_name\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this -> hackrf_usb_board_id_name = (pfn_hackrf_usb_board_id_name)
|
|
|
|
GETPROCADDRESS (Handle, "hackrf_usb_board_id_name");
|
|
|
|
if (this -> hackrf_usb_board_id_name == NULL) {
|
|
|
|
fprintf (stderr, "Could not find hackrf_usb_board_id_name\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (stderr, "OK, functions seem to be loaded\n");
|
|
|
|
return true;
|
|
|
|
}
|