From 78bd025335fc3c873dbaa184568a941a696549f7 Mon Sep 17 00:00:00 2001 From: JvanKatwijk Date: Sat, 17 Dec 2022 19:21:21 +0100 Subject: [PATCH] exp dev --- README.md | 2 + devices/airspy-handler/airspy-handler.cpp | 691 ++++++++++++++++++ devices/airspy-handler/airspy-handler.h | 163 +++++ devices/airspy-handler/airspy-widget.ui | 540 ++++++++++++++ devices/airspy-handler/libairspy/airspy.h | 219 ++++++ .../libairspy/airspy_commands.h | 145 ++++ devices/airspy-handler/libairspy/filters.h | 134 ++++ .../libairspy/iqconverter_float.h | 47 ++ .../libairspy/iqconverter_int16.h | 45 ++ qt-1090.cpp | 29 +- qt-1090.pro | 14 + 11 files changed, 2023 insertions(+), 6 deletions(-) create mode 100644 devices/airspy-handler/airspy-handler.cpp create mode 100644 devices/airspy-handler/airspy-handler.h create mode 100644 devices/airspy-handler/airspy-widget.ui create mode 100644 devices/airspy-handler/libairspy/airspy.h create mode 100644 devices/airspy-handler/libairspy/airspy_commands.h create mode 100644 devices/airspy-handler/libairspy/filters.h create mode 100644 devices/airspy-handler/libairspy/iqconverter_float.h create mode 100644 devices/airspy-handler/libairspy/iqconverter_int16.h diff --git a/README.md b/README.md index 8aa4512..2952e4a 100755 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ edit qt-1090.pro to select your device(s) by commenting out or uncommenting CONFIG += sdrplay-v3 CONFIG += dabstick CONFIG += hackrf + CONFIG += lime + CONFIG += pluto Later versions will include driver support for the Adalm pluto and the lime device. diff --git a/devices/airspy-handler/airspy-handler.cpp b/devices/airspy-handler/airspy-handler.cpp new file mode 100644 index 0000000..52203ec --- /dev/null +++ b/devices/airspy-handler/airspy-handler.cpp @@ -0,0 +1,691 @@ + +/** + * IW0HDV Extio + * + * Copyright 2015 by Andrea Montefusco IW0HDV + * + * Licensed under GNU General Public License 3.0 or later. + * Some rights reserved. See COPYING, AUTHORS. + * + * @license GPL-3.0+ + * + * recoding, taking parts and extending for the airspyHandler interface + * for the SDR-J-DAB receiver. + * jan van Katwijk + * Lazy Chair Computing + */ + +#ifdef __MINGW32__ +#define GETPROCADDRESS GetProcAddress +#else +#define GETPROCADDRESS dlsym +#endif + +#include "airspy-handler.h" + +static +const int EXTIO_NS = 8192; +static +const int EXTIO_BASE_TYPE_SIZE = sizeof (float); + + airspyHandler::airspyHandler (QSettings *s, int freq): + _I_Buffer (16 * 32768) { +int result, i; +QString h; +int k; +int distance = 10000000; +uint32_t myBuffer [20]; +uint32_t samplerate_count; + + this -> airspySettings = s; + this -> frequency = freq; + + this -> myFrame = new QFrame (nullptr); + setupUi (this -> myFrame); + this -> myFrame -> show (); + + inputRate = 2500000; + + airspySettings -> beginGroup ("airspyHandler"); + int16_t temp = airspySettings -> value ("linearity", 10). + toInt (); + linearitySlider -> setValue (temp); + linearityDisplay -> display (temp); + temp = airspySettings -> value ("sensitivity", 10). + toInt (); + sensitivitySlider -> setValue (temp); + sensitivityDisplay -> display (temp); + vgaGain = airspySettings -> value ("vga", 5).toInt (); + vgaSlider -> setValue (vgaGain); + vgaDisplay -> display (vgaGain); + mixerGain = airspySettings -> value ("mixer", 10). toInt (); + mixerSlider -> setValue (mixerGain); + mixerDisplay -> display (mixerGain); + mixer_agc = false; + lnaGain = airspySettings -> value ("lna", 5). toInt (); + lnaSlider -> setValue (lnaGain); + lnaDisplay -> display (lnaGain); + mixer_agc = false; + lna_agc = false; + rf_bias = false; + airspySettings -> endGroup (); +// + device = 0; + serialNumber = 0; +#ifdef __MINGW32__ + const char *libraryString = "airspy.dll"; + Handle = LoadLibrary ((wchar_t *)L"airspy.dll"); +#else + const char *libraryString = "libairspy.so"; + Handle = dlopen ("libusb-1.0.so", RTLD_NOW | RTLD_GLOBAL); + if (Handle == nullptr) { + fprintf (stderr, "libusb cannot be loaded\n"); + throw (22); + } + + Handle = dlopen ("libairspy.so", RTLD_LAZY); +#endif + + if (Handle == nullptr) { + fprintf (stderr, "failed to open %s\n", libraryString); +#ifndef __MINGW32__ + fprintf (stderr, "Error = %s\n", dlerror ()); +#endif + throw (23); + } + libraryLoaded = true; + + if (!load_airspyFunctions ()) { + fprintf (stderr, "problem in loading functions\n"); + throw (24); + } +// + strcpy (serial,""); + result = this -> my_airspy_init (); + if (result != AIRSPY_SUCCESS) { + printf ("my_airspy_init () failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + throw (25); + } + + result = my_airspy_open (&device); + if (result != AIRSPY_SUCCESS) { + printf ("my_airpsy_open () failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + throw (26); + } +// +// extract the rates + + (void) my_airspy_get_samplerates (device, &samplerate_count, 0); + fprintf (stderr, "%d samplerates are supported\n", samplerate_count); + my_airspy_get_samplerates (device, myBuffer, samplerate_count); + + inputRate = 0; + for (i = 0; i < samplerate_count; i ++) { + fprintf (stderr, "%d \n", myBuffer [i]); + if (abs ((int)(myBuffer [i]) - 2000000) < distance) { + distance = abs ((int)(myBuffer [i]) - 2000000); + inputRate = myBuffer [i]; + } + } + +// The sizes of the mapTables follow from the input and output rate +// (selectedRate / 1000) vs (2048000 / 1000) +// so we end up with buffers with 1 msec content + convBufferSize = inputRate / 1000; + for (i = 0; i < 2400; i ++) { + float inVal = float (inputRate / 1000); + mapTable_int [i] = int (floor (i * (inVal / 2400.0))); + mapTable_float [i] = i * (inVal / 2400.0) - mapTable_int [i]; + } + convIndex = 0; + convBuffer. resize (convBufferSize + 1); +// + connect (linearitySlider, SIGNAL (valueChanged (int)), + this, SLOT (set_linearity (int))); + connect (sensitivitySlider, SIGNAL (valueChanged (int)), + this, SLOT (set_sensitivity (int))); + connect (lnaSlider, SIGNAL (valueChanged (int)), + this, SLOT (set_lna_gain (int))); + connect (vgaSlider, SIGNAL (valueChanged (int)), + this, SLOT (set_vga_gain (int))); + connect (mixerSlider, SIGNAL (valueChanged (int)), + this, SLOT (set_mixer_gain (int))); + + connect (lnaButton, SIGNAL (clicked (void)), + this, SLOT (set_lna_agc (void))); + connect (mixerButton, SIGNAL (clicked (void)), + this, SLOT (set_mixer_agc (void))); + connect (biasButton, SIGNAL (clicked (void)), + this, SLOT (set_rf_bias (void))); + connect (tabWidget, SIGNAL (currentChanged (int)), + this, SLOT (show_tab (int))); + + displaySerial -> setText (getSerial ()); + show_tab (0); + running = false; +} + + airspyHandler::~airspyHandler () { + airspySettings -> beginGroup ("airspyHandler"); + airspySettings -> setValue ("linearity", linearitySlider -> value ()); + airspySettings -> setValue ("sensitivity", sensitivitySlider -> value ()); + airspySettings -> setValue ("vga", vgaGain); + airspySettings -> setValue ("mixer", mixerGain); + airspySettings -> setValue ("lna", lnaGain); + airspySettings -> endGroup (); + myFrame -> hide (); + if (Handle == nullptr) + goto err; + if (device) { + int result = my_airspy_stop_rx (device); + if (result != AIRSPY_SUCCESS) { + printf ("my_airspy_stop_rx () failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + } + + if (rf_bias) + set_rf_bias (); + result = my_airspy_close (device); + if (result != AIRSPY_SUCCESS) { + printf ("airspy_close () failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + } + } + my_airspy_exit (); + if (Handle != NULL) +#ifdef __MINGW32__ + FreeLibrary (Handle); +#else + dlclose (Handle); +#endif +err: + delete myFrame; +} + +void airspyHandler::startDevice () { +int result; +int32_t bufSize = EXTIO_NS * EXTIO_BASE_TYPE_SIZE * 2; + if (running) + return; + + _I_Buffer. FlushRingBuffer (); + if (currentTab == 0) + set_sensitivity (sensitivitySlider -> value ()); + else + if (currentTab == 1) + set_linearity (linearitySlider -> value ()); + else { + set_vga_gain (vgaGain); + set_mixer_gain (mixerGain); + set_lna_gain (lnaGain); + } + + result = my_airspy_set_sample_type (device, AIRSPY_SAMPLE_INT16_IQ); + if (result != AIRSPY_SUCCESS) { + printf ("my_airspy_set_sample_type () failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + return; + } + result = my_airspy_set_freq (device, this -> frequency); + + set_linearity (linearitySlider -> value ()); + set_sensitivity (sensitivitySlider -> value ()); + + result = my_airspy_start_rx (device, + (airspy_sample_block_cb_fn)callback, this); + if (result != AIRSPY_SUCCESS) { + printf ("my_airspy_start_rx () failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + return; + } +// +// finally: + buffer = new uint8_t [bufSize]; + bs_ = bufSize; + bl_ = 0; + running = true; +} + +void airspyHandler::stopDevice (void) { + if (!running) + return; +int result = my_airspy_stop_rx (device); + + if (result != AIRSPY_SUCCESS ) { + printf ("my_airspy_stop_rx() failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + } else { + delete [] buffer; + bs_ = bl_ = 0 ; + } + running = false; +} +// +// Directly copied from the airspy extio dll from Andrea Montefusco +int airspyHandler::callback (airspy_transfer* transfer) { +airspyHandler *p; + + if (!transfer) + return 0; // should not happen + p = static_cast (transfer -> ctx); + +// AIRSPY_SAMPLE_FLOAT32_IQ: + uint32_t bytes_to_write = transfer -> sample_count * 4 * 2; + uint8_t *pt_rx_buffer = (uint8_t *)transfer->samples; + + while (bytes_to_write > 0) { + int spaceleft = p -> bs_ - p -> bl_ ; + int to_copy = std::min ((int)spaceleft, (int)bytes_to_write); + ::memcpy (p -> buffer + p -> bl_, pt_rx_buffer, to_copy); + bytes_to_write -= to_copy; + pt_rx_buffer += to_copy; +// +// bs (i.e. buffersize) in bytes + if (p -> bl_ == p -> bs_) { + p -> data_available ((void *)p -> buffer, p -> bl_); + p->bl_ = 0; + } + p -> bl_ += to_copy; + } + return 0; +} + +// called from AIRSPY data callback +// this method is declared in airspyHandler class +// The buffer received from hardware contains +// 32-bit floating point IQ samples (8 bytes per sample) +// +// recoded for the sdr-j framework +// 4*2 = 8 bytes for sample, as per AirSpy USB data stream format +// we do the rate conversion here, read in groups of 625 samples +// and transform them into groups of 512 samples +static inline +std::complex cmul (std::complex a, float b) { + return std::complex (real (a) * b, imag (a) * b); +} + +int airspyHandler::data_available (void *buf, int buf_size) { +float *sbuf = (float *)buf; +int nSamples = buf_size / (sizeof (float) * 2); +std::complex temp [2400]; + + for (int i = 0; i < nSamples; i ++) { + convBuffer [convIndex ++] = std::complex (sbuf [2 * i], + sbuf [2 * i + 1]); + if (convIndex > convBufferSize) { + for (int j = 0; j < 2400; j ++) { + int16_t inpBase = mapTable_int [j]; + float inpRatio = mapTable_float [j]; + temp [j] = cmul (convBuffer [inpBase + 1], inpRatio) + + cmul (convBuffer [inpBase], 1 - inpRatio); + } + _I_Buffer. putDataIntoBuffer (temp, 2400); + if (_I_Buffer. GetRingBufferReadAvailable () > 250000) + signalData (); + +// shift the sample at the end to the beginning, it is needed +// as the starting sample for the next time + convBuffer [0] = convBuffer [convBufferSize]; + convIndex = 1; + } + } +} +// +const char *airspyHandler::getSerial (void) { +airspy_read_partid_serialno_t read_partid_serialno; +int result = my_airspy_board_partid_serialno_read (device, + &read_partid_serialno); + if (result != AIRSPY_SUCCESS) { + printf ("failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + return "UNKNOWN"; + } else { + snprintf (serial, sizeof(serial), "%08X%08X", + read_partid_serialno. serial_no [2], + read_partid_serialno. serial_no [3]); + } + return serial; +} +// +// not used here +int airspyHandler::open (void) { +int result = my_airspy_open (&device); + + if (result != AIRSPY_SUCCESS) { + printf ("airspy_open() failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + return -1; + } else { + return 0; + } +} + +int airspyHandler::nrBits () { + return 12; +} + +int32_t airspyHandler::getSamples (std::complex *v, int32_t size) { + return _I_Buffer. getDataFromBuffer (v, size); +} + +int32_t airspyHandler::Samples (void) { + return _I_Buffer. GetRingBufferReadAvailable (); +} +// +// agc's +/* Parameter value: + 0=Disable LNA Automatic Gain Control + 1=Enable LNA Automatic Gain Control +*/ +void airspyHandler::set_lna_agc (void) { + lna_agc = !lna_agc; +int result = my_airspy_set_lna_agc (device, lna_agc ? 1 : 0); + + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_lna_agc() failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + } +} + +/* Parameter value: + 0=Disable MIXER Automatic Gain Control + 1=Enable MIXER Automatic Gain Control +*/ +void airspyHandler::set_mixer_agc (void) { + mixer_agc = !mixer_agc; + +int result = my_airspy_set_mixer_agc (device, mixer_agc ? 1 : 0); + + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_mixer_agc () failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + } +} + + +/* Parameter value shall be 0=Disable BiasT or 1=Enable BiasT */ +void airspyHandler::set_rf_bias (void) { + rf_bias = !rf_bias; +int result = my_airspy_set_rf_bias (device, rf_bias ? 1 : 0); + + if (result != AIRSPY_SUCCESS) { + printf("airspy_set_rf_bias() failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + } +} + + +const char* airspyHandler::board_id_name (void) { +uint8_t bid; + + if (my_airspy_board_id_read (device, &bid) == AIRSPY_SUCCESS) + return my_airspy_board_id_name ((airspy_board_id)bid); + else + return "UNKNOWN"; +} +// +// +bool airspyHandler::load_airspyFunctions (void) { +// +// link the required procedures + my_airspy_init = (pfn_airspy_init) + GETPROCADDRESS (Handle, "airspy_init"); + if (my_airspy_init == NULL) { + fprintf (stderr, "Could not find airspy_init\n"); + return false; + } + + my_airspy_exit = (pfn_airspy_exit) + GETPROCADDRESS (Handle, "airspy_exit"); + if (my_airspy_exit == NULL) { + fprintf (stderr, "Could not find airspy_exit\n"); + return false; + } + + my_airspy_open = (pfn_airspy_open) + GETPROCADDRESS (Handle, "airspy_open"); + if (my_airspy_open == NULL) { + fprintf (stderr, "Could not find airspy_open\n"); + return false; + } + + my_airspy_close = (pfn_airspy_close) + GETPROCADDRESS (Handle, "airspy_close"); + if (my_airspy_close == NULL) { + fprintf (stderr, "Could not find airspy_close\n"); + return false; + } + + my_airspy_get_samplerates = (pfn_airspy_get_samplerates) + GETPROCADDRESS (Handle, "airspy_get_samplerates"); + if (my_airspy_get_samplerates == NULL) { + fprintf (stderr, "Could not find airspy_get_samplerates\n"); + return false; + } + + my_airspy_set_samplerate = (pfn_airspy_set_samplerate) + GETPROCADDRESS (Handle, "airspy_set_samplerate"); + if (my_airspy_set_samplerate == NULL) { + fprintf (stderr, "Could not find airspy_set_samplerate\n"); + return false; + } + + my_airspy_start_rx = (pfn_airspy_start_rx) + GETPROCADDRESS (Handle, "airspy_start_rx"); + if (my_airspy_start_rx == NULL) { + fprintf (stderr, "Could not find airspy_start_rx\n"); + return false; + } + + my_airspy_stop_rx = (pfn_airspy_stop_rx) + GETPROCADDRESS (Handle, "airspy_stop_rx"); + if (my_airspy_stop_rx == NULL) { + fprintf (stderr, "Could not find airspy_stop_rx\n"); + return false; + } + + my_airspy_set_sample_type = (pfn_airspy_set_sample_type) + GETPROCADDRESS (Handle, "airspy_set_sample_type"); + if (my_airspy_set_sample_type == NULL) { + fprintf (stderr, "Could not find airspy_set_sample_type\n"); + return false; + } + + my_airspy_set_freq = (pfn_airspy_set_freq) + GETPROCADDRESS (Handle, "airspy_set_freq"); + if (my_airspy_set_freq == NULL) { + fprintf (stderr, "Could not find airspy_set_freq\n"); + return false; + } + + my_airspy_set_lna_gain = (pfn_airspy_set_lna_gain) + GETPROCADDRESS (Handle, "airspy_set_lna_gain"); + if (my_airspy_set_lna_gain == NULL) { + fprintf (stderr, "Could not find airspy_set_lna_gain\n"); + return false; + } + + my_airspy_set_mixer_gain = (pfn_airspy_set_mixer_gain) + GETPROCADDRESS (Handle, "airspy_set_mixer_gain"); + if (my_airspy_set_mixer_gain == NULL) { + fprintf (stderr, "Could not find airspy_set_mixer_gain\n"); + return false; + } + + my_airspy_set_vga_gain = (pfn_airspy_set_vga_gain) + GETPROCADDRESS (Handle, "airspy_set_vga_gain"); + if (my_airspy_set_vga_gain == NULL) { + fprintf (stderr, "Could not find airspy_set_vga_gain\n"); + return false; + } + + my_airspy_set_linearity_gain = (pfn_airspy_set_linearity_gain) + GETPROCADDRESS (Handle, "airspy_set_linearity_gain"); + if (my_airspy_set_linearity_gain == NULL) { + fprintf (stderr, "Could not find airspy_set_linearity_gain\n"); + fprintf (stderr, "You probably did not install 1.0.7 yet\n"); + return false; + } + + my_airspy_set_sensitivity_gain = (pfn_airspy_set_sensitivity_gain) + GETPROCADDRESS (Handle, "airspy_set_sensitivity_gain"); + if (my_airspy_set_sensitivity_gain == NULL) { + fprintf (stderr, "Could not find airspy_set_sensitivity_gain\n"); + fprintf (stderr, "You probably did not install 1.0.7 yet\n"); + return false; + } + + + my_airspy_set_lna_agc = (pfn_airspy_set_lna_agc) + GETPROCADDRESS (Handle, "airspy_set_lna_agc"); + if (my_airspy_set_lna_agc == NULL) { + fprintf (stderr, "Could not find airspy_set_lna_agc\n"); + return false; + } + + my_airspy_set_mixer_agc = (pfn_airspy_set_mixer_agc) + GETPROCADDRESS (Handle, "airspy_set_mixer_agc"); + if (my_airspy_set_mixer_agc == NULL) { + fprintf (stderr, "Could not find airspy_set_mixer_agc\n"); + return false; + } + + my_airspy_set_rf_bias = (pfn_airspy_set_rf_bias) + GETPROCADDRESS (Handle, "airspy_set_rf_bias"); + if (my_airspy_set_rf_bias == NULL) { + fprintf (stderr, "Could not find airspy_set_rf_bias\n"); + return false; + } + + my_airspy_error_name = (pfn_airspy_error_name) + GETPROCADDRESS (Handle, "airspy_error_name"); + if (my_airspy_error_name == NULL) { + fprintf (stderr, "Could not find airspy_error_name\n"); + return false; + } + + my_airspy_board_id_read = (pfn_airspy_board_id_read) + GETPROCADDRESS (Handle, "airspy_board_id_read"); + if (my_airspy_board_id_read == NULL) { + fprintf (stderr, "Could not find airspy_board_id_read\n"); + return false; + } + + my_airspy_board_id_name = (pfn_airspy_board_id_name) + GETPROCADDRESS (Handle, "airspy_board_id_name"); + if (my_airspy_board_id_name == NULL) { + fprintf (stderr, "Could not find airspy_board_id_name\n"); + return false; + } + + my_airspy_board_partid_serialno_read = + (pfn_airspy_board_partid_serialno_read) + GETPROCADDRESS (Handle, "airspy_board_partid_serialno_read"); + if (my_airspy_board_partid_serialno_read == NULL) { + fprintf (stderr, "Could not find airspy_board_partid_serialno_read\n"); + return false; + } + + return true; +} + + +/* Parameter value shall be between 0 and 15 */ +void airspyHandler::set_lna_gain (int value) { +int result = my_airspy_set_lna_gain (device, lnaGain = value); + + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_lna_gain () failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + } + else + lnaDisplay -> display (value); +} + +/* Parameter value shall be between 0 and 15 */ +void airspyHandler::set_mixer_gain (int value) { +int result = my_airspy_set_mixer_gain(device, mixerGain = value); + + if (result != AIRSPY_SUCCESS) { + printf("airspy_set_mixer_gain() failed: %s (%d)\n", + my_airspy_error_name((airspy_error)result), result); + } + else + mixerDisplay -> display (value); +} + +/* Parameter value shall be between 0 and 15 */ +void airspyHandler::set_vga_gain (int value) { +int result = my_airspy_set_vga_gain(device, vgaGain = value); + + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_vga_gain () failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + } + else + vgaDisplay -> display (value); +} + +#define GAIN_COUNT (22) + +uint8_t airspy_linearity_vga_gains[GAIN_COUNT] = { 13, 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4 }; +uint8_t airspy_linearity_mixer_gains[GAIN_COUNT] = { 12, 12, 11, 9, 8, 7, 6, 6, 5, 0, 0, 1, 0, 0, 2, 2, 1, 1, 1, 1, 0, 0 }; +uint8_t airspy_linearity_lna_gains[GAIN_COUNT] = { 14, 14, 14, 13, 12, 10, 9, 9, 8, 9, 8, 6, 5, 3, 1, 0, 0, 0, 0, 0, 0, 0 }; +uint8_t airspy_sensitivity_vga_gains[GAIN_COUNT] = { 13, 12, 11, 10, 9, 8, 7, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; +uint8_t airspy_sensitivity_mixer_gains[GAIN_COUNT] = { 12, 12, 12, 12, 11, 10, 10, 9, 9, 8, 7, 4, 4, 4, 3, 2, 2, 1, 0, 0, 0, 0 }; +uint8_t airspy_sensitivity_lna_gains[GAIN_COUNT] = { 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 12, 12, 9, 9, 8, 7, 6, 5, 3, 2, 1, 0 }; + +void airspyHandler::set_linearity (int value) { +int result = my_airspy_set_linearity_gain (device, value); +int temp; + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_lna_gain () failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + return; + } + linearityDisplay -> display (value); + temp = airspy_linearity_lna_gains [GAIN_COUNT - 1 - value]; + linearity_lnaDisplay -> display (temp); + temp = airspy_linearity_mixer_gains [GAIN_COUNT - 1 - value]; + linearity_mixerDisplay -> display (temp); + temp = airspy_linearity_vga_gains [GAIN_COUNT - 1 - value]; + linearity_vgaDisplay -> display (temp); +} + +void airspyHandler::set_sensitivity (int value) { +int result = my_airspy_set_sensitivity_gain (device, value); +int temp; + if (result != AIRSPY_SUCCESS) { + printf ("airspy_set_mixer_gain() failed: %s (%d)\n", + my_airspy_error_name ((airspy_error)result), result); + return; + } + sensitivityDisplay -> display (value); + temp = airspy_sensitivity_lna_gains [GAIN_COUNT - 1 - value]; + sensitivity_lnaDisplay -> display (temp); + temp = airspy_sensitivity_mixer_gains [GAIN_COUNT - 1 - value]; + sensitivity_mixerDisplay -> display (temp); + temp = airspy_sensitivity_vga_gains [GAIN_COUNT - 1 - value]; + sensitivity_vgaDisplay -> display (temp); +} + +void airspyHandler::show_tab (int t) { + if (t == 0) // sensitivity + set_sensitivity (sensitivitySlider -> value ()); + else + if (t == 1) // linearity + set_linearity (linearitySlider -> value ()); + else { // classic view + set_vga_gain (vgaGain); + set_mixer_gain (mixerGain); + set_lna_gain (lnaGain); + } + currentTab = t; +} + +void airspyHandler::signalData () { + emit dataAvailable (); +} + diff --git a/devices/airspy-handler/airspy-handler.h b/devices/airspy-handler/airspy-handler.h new file mode 100644 index 0000000..4cbcfec --- /dev/null +++ b/devices/airspy-handler/airspy-handler.h @@ -0,0 +1,163 @@ + +/** + * IW0HDV Extio + * + * Copyright 2015 by Andrea Montefusco IW0HDV + * + * Licensed under GNU General Public License 3.0 or later. + * Some rights reserved. See COPYING, AUTHORS. + * + * @license GPL-3.0+ + * + * recoding and taking parts for the airspyRadio interface + * for the SDR-J-FM receiver + * jan van Katwijk + * Lazy Chair Computing + */ +#ifndef __AIRSPY_RADIO__ +#define __AIRSPY_RADIO__ + +#include +#include +#include +#include "ringbuffer.h" +#include "device-handler.h" +#include "ui_airspy-widget.h" +#include "airspy.h" + +extern "C" { +typedef int (*pfn_airspy_init) (void); +typedef int (*pfn_airspy_exit) (void); +typedef int (*pfn_airspy_open) (struct airspy_device**); +typedef int (*pfn_airspy_close) (struct airspy_device*); +typedef int (*pfn_airspy_get_samplerates) (struct airspy_device* device, + uint32_t* buffer, + const uint32_t len); +typedef int (*pfn_airspy_set_samplerate) (struct airspy_device* device, + uint32_t samplerate); +typedef int (*pfn_airspy_start_rx) (struct airspy_device* device, + airspy_sample_block_cb_fn callback, + void* rx_ctx); +typedef int (*pfn_airspy_stop_rx) (struct airspy_device* device); + +typedef int (*pfn_airspy_set_sample_type) (struct airspy_device *, + airspy_sample_type); +typedef int (*pfn_airspy_set_freq) (struct airspy_device* device, + const uint32_t freq_hz); + +typedef int (*pfn_airspy_set_lna_gain) (struct airspy_device* device, + uint8_t value); + +typedef int (*pfn_airspy_set_mixer_gain) (struct airspy_device* device, + uint8_t value); + +typedef int (*pfn_airspy_set_vga_gain) (struct airspy_device* + device, uint8_t + value); +typedef int (*pfn_airspy_set_lna_agc) (struct airspy_device* device, + uint8_t value); +typedef int (*pfn_airspy_set_mixer_agc) (struct airspy_device* device, + uint8_t value); + +typedef int (*pfn_airspy_set_rf_bias) (struct airspy_device* dev, + uint8_t value); + +typedef const char* (*pfn_airspy_error_name) (enum airspy_error errcode); +typedef int (*pfn_airspy_board_id_read) (struct airspy_device *, + uint8_t *); +typedef const char* (*pfn_airspy_board_id_name) (enum airspy_board_id board_id); +typedef int (*pfn_airspy_board_partid_serialno_read)(struct airspy_device* device, airspy_read_partid_serialno_t* read_partid_serialno); + +typedef int (*pfn_airspy_set_linearity_gain) (struct airspy_device* device, uint8_t value); +typedef int (*pfn_airspy_set_sensitivity_gain)(struct airspy_device* device, uint8_t value); +} + +class airspyHandler: public deviceHandler, public Ui_airspyWidget { +Q_OBJECT +public: + airspyHandler (QSettings *, int); + ~airspyHandler (); + void startDevice (); + void stopDevice (); + int32_t getSamples (std::complex *v, int32_t size); + int32_t Samples (); + int nrBits (); +// + int16_t currentTab; +private slots: + void set_linearity (int value); + void set_sensitivity (int value); + void set_lna_gain (int value); + void set_mixer_gain (int value); + void set_vga_gain (int value); + void set_lna_agc (void); + void set_mixer_agc (void); + void set_rf_bias (void); + void show_tab (int); + +private: + RingBuffer> _I_Buffer; + bool load_airspyFunctions (void); + int frequency; +// The functions to be extracted from the dll/.so file + pfn_airspy_init my_airspy_init; + pfn_airspy_exit my_airspy_exit; + pfn_airspy_open my_airspy_open; + pfn_airspy_close my_airspy_close; + pfn_airspy_get_samplerates my_airspy_get_samplerates; + pfn_airspy_set_samplerate my_airspy_set_samplerate; + pfn_airspy_start_rx my_airspy_start_rx; + pfn_airspy_stop_rx my_airspy_stop_rx; + pfn_airspy_set_sample_type my_airspy_set_sample_type; + pfn_airspy_set_freq my_airspy_set_freq; + pfn_airspy_set_lna_gain my_airspy_set_lna_gain; + pfn_airspy_set_mixer_gain my_airspy_set_mixer_gain; + pfn_airspy_set_vga_gain my_airspy_set_vga_gain; + pfn_airspy_set_linearity_gain my_airspy_set_linearity_gain; + pfn_airspy_set_sensitivity_gain my_airspy_set_sensitivity_gain; + pfn_airspy_set_lna_agc my_airspy_set_lna_agc; + pfn_airspy_set_mixer_agc my_airspy_set_mixer_agc; + pfn_airspy_set_rf_bias my_airspy_set_rf_bias; + pfn_airspy_error_name my_airspy_error_name; + pfn_airspy_board_id_read my_airspy_board_id_read; + pfn_airspy_board_id_name my_airspy_board_id_name; + pfn_airspy_board_partid_serialno_read + my_airspy_board_partid_serialno_read; +// + HINSTANCE Handle; + bool libraryLoaded; + QFrame *myFrame; + bool success; + bool running; + bool lna_agc; + bool mixer_agc; + bool rf_bias; +const char* board_id_name (void); + + int16_t vgaGain; + int16_t mixerGain; + int16_t lnaGain; + + void signalData (); + std::vector> convBuffer; + int16_t convIndex; + int convBufferSize; + int16_t mapTable_int [2400]; + float mapTable_float [2400]; + QSettings *airspySettings; + int32_t inputRate; + struct airspy_device* device; + uint64_t serialNumber; + char serial[128]; + // callback buffer + int bs_; + uint8_t *buffer; + int bl_; +static + int callback(airspy_transfer_t *); + int data_available (void *buf, int buf_size); +const char * getSerial (void); + int open (void); +}; + +#endif diff --git a/devices/airspy-handler/airspy-widget.ui b/devices/airspy-handler/airspy-widget.ui new file mode 100644 index 0000000..06f2cbf --- /dev/null +++ b/devices/airspy-handler/airspy-widget.ui @@ -0,0 +1,540 @@ + + + airspyWidget + + + + 0 + 0 + 423 + 302 + + + + airspy + + + + + 10 + 90 + 401 + 191 + + + + 0 + + + + sensitivity + + + + + 20 + 20 + 321 + 20 + + + + 21 + + + 10 + + + Qt::Horizontal + + + + + + 340 + 20 + 41 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 60 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 80 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 100 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 120 + 60 + 101 + 20 + + + + lna gain + + + + + + 120 + 80 + 91 + 20 + + + + mixer gain + + + + + + 120 + 100 + 81 + 20 + + + + vga gain + + + + + + linearity + + + + + 20 + 20 + 301 + 20 + + + + 21 + + + 10 + + + Qt::Horizontal + + + + + + 330 + 20 + 64 + 23 + + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 60 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 80 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 220 + 100 + 64 + 23 + + + + QFrame::NoFrame + + + 2 + + + QLCDNumber::Flat + + + + + + 100 + 60 + 91 + 20 + + + + lna gain + + + + + + 100 + 80 + 101 + 20 + + + + mixer gain + + + + + + 100 + 100 + 71 + 20 + + + + vga gain + + + + + + classic view + + + + + 100 + 10 + 221 + 20 + + + + 15 + + + 10 + + + Qt::Horizontal + + + + + + 10 + 10 + 66 + 20 + + + + lna + + + + + + 343 + 10 + 51 + 23 + + + + 2 + + + QLCDNumber::Flat + + + + + + 100 + 40 + 221 + 20 + + + + 15 + + + 10 + + + Qt::Horizontal + + + + + + 343 + 40 + 51 + 23 + + + + 2 + + + QLCDNumber::Flat + + + + + + 10 + 40 + 66 + 20 + + + + mixer + + + + + + 100 + 70 + 221 + 20 + + + + 15 + + + 10 + + + Qt::Horizontal + + + + + + 10 + 60 + 66 + 20 + + + + vga + + + + + + 343 + 70 + 51 + 23 + + + + 2 + + + QLCDNumber::Flat + + + + + + 20 + 110 + 61 + 32 + + + + lna + + + + + + 120 + 110 + 90 + 32 + + + + mixer + + + + + + 250 + 110 + 90 + 32 + + + + bias + + + + + + + + 100 + 60 + 241 + 21 + + + + + + + + + + 50 + 20 + 211 + 20 + + + + A I R S P Y handler + + + + + + 270 + 10 + 121 + 23 + + + + QFrame::NoFrame + + + 7 + + + QLCDNumber::Flat + + + + + + diff --git a/devices/airspy-handler/libairspy/airspy.h b/devices/airspy-handler/libairspy/airspy.h new file mode 100644 index 0000000..630424d --- /dev/null +++ b/devices/airspy-handler/libairspy/airspy.h @@ -0,0 +1,219 @@ +/* +Copyright (c) 2012, Jared Boone +Copyright (c) 2013, Michael Ossmann +Copyright (c) 2013-2016, Benjamin Vernoux +Copyright (C) 2013-2016, Youssef Touil + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + Neither the name of AirSpy nor the names of its contributors may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __AIRSPY_H__ +#define __AIRSPY_H__ + +#include +#include "airspy_commands.h" + +#define AIRSPY_VERSION "1.0.9" +#define AIRSPY_VER_MAJOR 1 +#define AIRSPY_VER_MINOR 0 +#define AIRSPY_VER_REVISION 9 + +#ifdef _WIN32 + #define ADD_EXPORTS + + /* You should define ADD_EXPORTS *only* when building the DLL. */ + #ifdef ADD_EXPORTS + #define ADDAPI __declspec(dllexport) + #else + #define ADDAPI __declspec(dllimport) + #endif + + /* Define calling convention in one place, for convenience. */ + #define ADDCALL __cdecl + +#else /* _WIN32 not defined. */ + + /* Define with no value on non-Windows OSes. */ + #define ADDAPI + #define ADDCALL + +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum airspy_error +{ + AIRSPY_SUCCESS = 0, + AIRSPY_TRUE = 1, + AIRSPY_ERROR_INVALID_PARAM = -2, + AIRSPY_ERROR_NOT_FOUND = -5, + AIRSPY_ERROR_BUSY = -6, + AIRSPY_ERROR_NO_MEM = -11, + AIRSPY_ERROR_LIBUSB = -1000, + AIRSPY_ERROR_THREAD = -1001, + AIRSPY_ERROR_STREAMING_THREAD_ERR = -1002, + AIRSPY_ERROR_STREAMING_STOPPED = -1003, + AIRSPY_ERROR_OTHER = -9999, +}; + +enum airspy_board_id +{ + AIRSPY_BOARD_ID_PROTO_AIRSPY = 0, + AIRSPY_BOARD_ID_INVALID = 0xFF, +}; + +enum airspy_sample_type +{ + AIRSPY_SAMPLE_FLOAT32_IQ = 0, /* 2 * 32bit float per sample */ + AIRSPY_SAMPLE_FLOAT32_REAL = 1, /* 1 * 32bit float per sample */ + AIRSPY_SAMPLE_INT16_IQ = 2, /* 2 * 16bit int per sample */ + AIRSPY_SAMPLE_INT16_REAL = 3, /* 1 * 16bit int per sample */ + AIRSPY_SAMPLE_UINT16_REAL = 4, /* 1 * 16bit unsigned int per sample */ + AIRSPY_SAMPLE_RAW = 5, /* Raw packed samples from the device */ + AIRSPY_SAMPLE_END = 6 /* Number of supported sample types */ +}; + +#define MAX_CONFIG_PAGE_SIZE (0x10000) + +struct airspy_device; + +typedef struct { + struct airspy_device* device; + void* ctx; + void* samples; + int sample_count; + uint64_t dropped_samples; + enum airspy_sample_type sample_type; +} airspy_transfer_t, airspy_transfer; + +typedef struct { + uint32_t part_id[2]; + uint32_t serial_no[4]; +} airspy_read_partid_serialno_t; + +typedef struct { + uint32_t major_version; + uint32_t minor_version; + uint32_t revision; +} airspy_lib_version_t; + +typedef int (*airspy_sample_block_cb_fn)(airspy_transfer* transfer); + +extern ADDAPI void ADDCALL airspy_lib_version(airspy_lib_version_t* lib_version); +/* airspy_init() deprecated */ +extern ADDAPI int ADDCALL airspy_init(void); +/* airspy_exit() deprecated */ +extern ADDAPI int ADDCALL airspy_exit(void); + +extern ADDAPI int ADDCALL airspy_open_sn(struct airspy_device** device, uint64_t serial_number); +extern ADDAPI int ADDCALL airspy_open(struct airspy_device** device); +extern ADDAPI int ADDCALL airspy_close(struct airspy_device* device); + +extern ADDAPI int ADDCALL airspy_get_samplerates(struct airspy_device* device, uint32_t* buffer, const uint32_t len); + +/* Parameter samplerate can be either the index of a samplerate or directly its value in Hz within the list returned by airspy_get_samplerates() */ +extern ADDAPI int ADDCALL airspy_set_samplerate(struct airspy_device* device, uint32_t samplerate); + +extern ADDAPI int ADDCALL airspy_set_conversion_filter_float32(struct airspy_device* device, const float *kernel, const uint32_t len); +extern ADDAPI int ADDCALL airspy_set_conversion_filter_int16(struct airspy_device* device, const int16_t *kernel, const uint32_t len); + +extern ADDAPI int ADDCALL airspy_start_rx(struct airspy_device* device, airspy_sample_block_cb_fn callback, void* rx_ctx); +extern ADDAPI int ADDCALL airspy_stop_rx(struct airspy_device* device); + +/* return AIRSPY_TRUE if success */ +extern ADDAPI int ADDCALL airspy_is_streaming(struct airspy_device* device); + +extern ADDAPI int ADDCALL airspy_si5351c_write(struct airspy_device* device, uint8_t register_number, uint8_t value); +extern ADDAPI int ADDCALL airspy_si5351c_read(struct airspy_device* device, uint8_t register_number, uint8_t* value); + +extern ADDAPI int ADDCALL airspy_config_write(struct airspy_device* device, const uint8_t page_index, const uint16_t length, unsigned char *data); +extern ADDAPI int ADDCALL airspy_config_read(struct airspy_device* device, const uint8_t page_index, const uint16_t length, unsigned char *data); + +extern ADDAPI int ADDCALL airspy_r820t_write(struct airspy_device* device, uint8_t register_number, uint8_t value); +extern ADDAPI int ADDCALL airspy_r820t_read(struct airspy_device* device, uint8_t register_number, uint8_t* value); + +/* Parameter value shall be 0=clear GPIO or 1=set GPIO */ +extern ADDAPI int ADDCALL airspy_gpio_write(struct airspy_device* device, airspy_gpio_port_t port, airspy_gpio_pin_t pin, uint8_t value); +/* Parameter value corresponds to GPIO state 0 or 1 */ +extern ADDAPI int ADDCALL airspy_gpio_read(struct airspy_device* device, airspy_gpio_port_t port, airspy_gpio_pin_t pin, uint8_t* value); + +/* Parameter value shall be 0=GPIO Input direction or 1=GPIO Output direction */ +extern ADDAPI int ADDCALL airspy_gpiodir_write(struct airspy_device* device, airspy_gpio_port_t port, airspy_gpio_pin_t pin, uint8_t value); +extern ADDAPI int ADDCALL airspy_gpiodir_read(struct airspy_device* device, airspy_gpio_port_t port, airspy_gpio_pin_t pin, uint8_t* value); + +extern ADDAPI int ADDCALL airspy_spiflash_erase(struct airspy_device* device); +extern ADDAPI int ADDCALL airspy_spiflash_write(struct airspy_device* device, const uint32_t address, const uint16_t length, unsigned char* const data); +extern ADDAPI int ADDCALL airspy_spiflash_read(struct airspy_device* device, const uint32_t address, const uint16_t length, unsigned char* data); + +extern ADDAPI int ADDCALL airspy_board_id_read(struct airspy_device* device, uint8_t* value); +/* Parameter length shall be at least 128bytes */ +extern ADDAPI int ADDCALL airspy_version_string_read(struct airspy_device* device, char* version, uint8_t length); + +extern ADDAPI int ADDCALL airspy_board_partid_serialno_read(struct airspy_device* device, airspy_read_partid_serialno_t* read_partid_serialno); + +extern ADDAPI int ADDCALL airspy_set_sample_type(struct airspy_device* device, enum airspy_sample_type sample_type); + +/* Parameter freq_hz shall be between 24000000(24MHz) and 1750000000(1.75GHz) */ +extern ADDAPI int ADDCALL airspy_set_freq(struct airspy_device* device, const uint32_t freq_hz); + +/* Parameter value shall be between 0 and 15 */ +extern ADDAPI int ADDCALL airspy_set_lna_gain(struct airspy_device* device, uint8_t value); + +/* Parameter value shall be between 0 and 15 */ +extern ADDAPI int ADDCALL airspy_set_mixer_gain(struct airspy_device* device, uint8_t value); + +/* Parameter value shall be between 0 and 15 */ +extern ADDAPI int ADDCALL airspy_set_vga_gain(struct airspy_device* device, uint8_t value); + +/* Parameter value: + 0=Disable LNA Automatic Gain Control + 1=Enable LNA Automatic Gain Control +*/ +extern ADDAPI int ADDCALL airspy_set_lna_agc(struct airspy_device* device, uint8_t value); +/* Parameter value: + 0=Disable MIXER Automatic Gain Control + 1=Enable MIXER Automatic Gain Control +*/ +extern ADDAPI int ADDCALL airspy_set_mixer_agc(struct airspy_device* device, uint8_t value); + +/* Parameter value: 0..21 */ +extern ADDAPI int ADDCALL airspy_set_linearity_gain(struct airspy_device* device, uint8_t value); + +/* Parameter value: 0..21 */ +extern ADDAPI int ADDCALL airspy_set_sensitivity_gain(struct airspy_device* device, uint8_t value); + +/* Parameter value shall be 0=Disable BiasT or 1=Enable BiasT */ +extern ADDAPI int ADDCALL airspy_set_rf_bias(struct airspy_device* dev, uint8_t value); + +/* Parameter value shall be 0=Disable Packing or 1=Enable Packing */ +extern ADDAPI int ADDCALL airspy_set_packing(struct airspy_device* device, uint8_t value); + +extern ADDAPI const char* ADDCALL airspy_error_name(enum airspy_error errcode); +extern ADDAPI const char* ADDCALL airspy_board_id_name(enum airspy_board_id board_id); + +/* Parameter sector_num shall be between 2 & 13 (sector 0 & 1 are reserved) */ +extern ADDAPI int ADDCALL airspy_spiflash_erase_sector(struct airspy_device* device, const uint16_t sector_num); + +#ifdef __cplusplus +} // __cplusplus defined. +#endif + +#endif//__AIRSPY_H__ diff --git a/devices/airspy-handler/libairspy/airspy_commands.h b/devices/airspy-handler/libairspy/airspy_commands.h new file mode 100644 index 0000000..21194f8 --- /dev/null +++ b/devices/airspy-handler/libairspy/airspy_commands.h @@ -0,0 +1,145 @@ +/* +Copyright (c) 2013-2016, Benjamin Vernoux + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + Neither the name of AirSpy nor the names of its contributors may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __AIRSPY_COMMANDS_H__ +#define __AIRSPY_COMMANDS_H__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum +{ + RECEIVER_MODE_OFF = 0, + RECEIVER_MODE_RX = 1 +} receiver_mode_t; + +/* + Note: airspy_samplerate_t is now obsolete and left for backward compatibility. + The list of supported sample rates should be retrieved at run time by calling airspy_get_samplerates(). + Refer to the Airspy Tools for illustrations. +*/ +typedef enum +{ + AIRSPY_SAMPLERATE_10MSPS = 0, /* 12bits 10MHz IQ */ + AIRSPY_SAMPLERATE_2_5MSPS = 1, /* 12bits 2.5MHz IQ */ + AIRSPY_SAMPLERATE_END = 2 /* End index for sample rate (corresponds to number of samplerate) */ +} airspy_samplerate_t; + + +#define AIRSPY_CONF_CMD_SHIFT_BIT (3) // Up to 3bits=8 samplerates (airspy_samplerate_t enum shall not exceed 7) + +// Commands (usb vendor request) shared between Firmware and Host. +#define AIRSPY_CMD_MAX (27) +typedef enum +{ + AIRSPY_INVALID = 0 , + AIRSPY_RECEIVER_MODE = 1 , + AIRSPY_SI5351C_WRITE = 2 , + AIRSPY_SI5351C_READ = 3 , + AIRSPY_R820T_WRITE = 4 , + AIRSPY_R820T_READ = 5 , + AIRSPY_SPIFLASH_ERASE = 6 , + AIRSPY_SPIFLASH_WRITE = 7 , + AIRSPY_SPIFLASH_READ = 8 , + AIRSPY_BOARD_ID_READ = 9 , + AIRSPY_VERSION_STRING_READ = 10, + AIRSPY_BOARD_PARTID_SERIALNO_READ = 11, + AIRSPY_SET_SAMPLERATE = 12, + AIRSPY_SET_FREQ = 13, + AIRSPY_SET_LNA_GAIN = 14, + AIRSPY_SET_MIXER_GAIN = 15, + AIRSPY_SET_VGA_GAIN = 16, + AIRSPY_SET_LNA_AGC = 17, + AIRSPY_SET_MIXER_AGC = 18, + AIRSPY_MS_VENDOR_CMD = 19, + AIRSPY_SET_RF_BIAS_CMD = 20, + AIRSPY_GPIO_WRITE = 21, + AIRSPY_GPIO_READ = 22, + AIRSPY_GPIODIR_WRITE = 23, + AIRSPY_GPIODIR_READ = 24, + AIRSPY_GET_SAMPLERATES = 25, + AIRSPY_SET_PACKING = 26, + AIRSPY_SPIFLASH_ERASE_SECTOR = AIRSPY_CMD_MAX +} airspy_vendor_request; + +typedef enum +{ + CONFIG_CALIBRATION = 0, + //CONFIG_META = 1, +} airspy_common_config_pages_t; + +typedef enum +{ + GPIO_PORT0 = 0, + GPIO_PORT1 = 1, + GPIO_PORT2 = 2, + GPIO_PORT3 = 3, + GPIO_PORT4 = 4, + GPIO_PORT5 = 5, + GPIO_PORT6 = 6, + GPIO_PORT7 = 7 +} airspy_gpio_port_t; + +typedef enum +{ + GPIO_PIN0 = 0, + GPIO_PIN1 = 1, + GPIO_PIN2 = 2, + GPIO_PIN3 = 3, + GPIO_PIN4 = 4, + GPIO_PIN5 = 5, + GPIO_PIN6 = 6, + GPIO_PIN7 = 7, + GPIO_PIN8 = 8, + GPIO_PIN9 = 9, + GPIO_PIN10 = 10, + GPIO_PIN11 = 11, + GPIO_PIN12 = 12, + GPIO_PIN13 = 13, + GPIO_PIN14 = 14, + GPIO_PIN15 = 15, + GPIO_PIN16 = 16, + GPIO_PIN17 = 17, + GPIO_PIN18 = 18, + GPIO_PIN19 = 19, + GPIO_PIN20 = 20, + GPIO_PIN21 = 21, + GPIO_PIN22 = 22, + GPIO_PIN23 = 23, + GPIO_PIN24 = 24, + GPIO_PIN25 = 25, + GPIO_PIN26 = 26, + GPIO_PIN27 = 27, + GPIO_PIN28 = 28, + GPIO_PIN29 = 29, + GPIO_PIN30 = 30, + GPIO_PIN31 = 31 +} airspy_gpio_pin_t; + +#ifdef __cplusplus +} // __cplusplus defined. +#endif + +#endif//__AIRSPY_COMMANDS_H__ diff --git a/devices/airspy-handler/libairspy/filters.h b/devices/airspy-handler/libairspy/filters.h new file mode 100644 index 0000000..30da6e4 --- /dev/null +++ b/devices/airspy-handler/libairspy/filters.h @@ -0,0 +1,134 @@ +/* +Copyright (C) 2014, Youssef Touil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef FILTERS_H +#define FILTERS_H + +#include + +#define HB_KERNEL_FLOAT_LEN 47 + +const float HB_KERNEL_FLOAT[HB_KERNEL_FLOAT_LEN] = +{ + -0.000998606272947510, + 0.000000000000000000, + 0.001695637278417295, + 0.000000000000000000, + -0.003054430179754289, + 0.000000000000000000, + 0.005055504379767936, + 0.000000000000000000, + -0.007901319195893647, + 0.000000000000000000, + 0.011873357051047719, + 0.000000000000000000, + -0.017411159379930066, + 0.000000000000000000, + 0.025304817427568772, + 0.000000000000000000, + -0.037225225204559217, + 0.000000000000000000, + 0.057533286997004301, + 0.000000000000000000, + -0.102327462004259350, + 0.000000000000000000, + 0.317034472508947400, + 0.500000000000000000, + 0.317034472508947400, + 0.000000000000000000, + -0.102327462004259350, + 0.000000000000000000, + 0.057533286997004301, + 0.000000000000000000, + -0.037225225204559217, + 0.000000000000000000, + 0.025304817427568772, + 0.000000000000000000, + -0.017411159379930066, + 0.000000000000000000, + 0.011873357051047719, + 0.000000000000000000, + -0.007901319195893647, + 0.000000000000000000, + 0.005055504379767936, + 0.000000000000000000, + -0.003054430179754289, + 0.000000000000000000, + 0.001695637278417295, + 0.000000000000000000, + -0.000998606272947510 +}; + +#define HB_KERNEL_INT16_LEN 47 + +const int16_t HB_KERNEL_INT16[HB_KERNEL_INT16_LEN] = +{ + -33, + 0, + 56, + 0, + -100, + 0, + 166, + 0, + -259, + 0, + 389, + 0, + -571, + 0, + 829, + 0, + -1220, + 0, + 1885, + 0, + -3353, + 0, + 10389, + 16384, + 10389, + 0, + -3353, + 0, + 1885, + 0, + -1220, + 0, + 829, + 0, + -571, + 0, + 389, + 0, + -259, + 0, + 166, + 0, + -100, + 0, + 56, + 0, + -33 +}; + +#endif // FILTERS_H diff --git a/devices/airspy-handler/libairspy/iqconverter_float.h b/devices/airspy-handler/libairspy/iqconverter_float.h new file mode 100644 index 0000000..f82b8b3 --- /dev/null +++ b/devices/airspy-handler/libairspy/iqconverter_float.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2014, Youssef Touil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef IQCONVERTER_FLOAT_H +#define IQCONVERTER_FLOAT_H + +#include + +#define IQCONVERTER_NZEROS 2 +#define IQCONVERTER_NPOLES 2 + +typedef struct { + float avg; + float hbc; + int len; + int fir_index; + int delay_index; + float *fir_kernel; + float *fir_queue; + float *delay_line; +} iqconverter_float_t; + +iqconverter_float_t *iqconverter_float_create(const float *hb_kernel, int len); +void iqconverter_float_free(iqconverter_float_t *cnv); +void iqconverter_float_reset(iqconverter_float_t *cnv); +void iqconverter_float_process(iqconverter_float_t *cnv, float *samples, int len); + +#endif // IQCONVERTER_FLOAT_H diff --git a/devices/airspy-handler/libairspy/iqconverter_int16.h b/devices/airspy-handler/libairspy/iqconverter_int16.h new file mode 100644 index 0000000..10c867d --- /dev/null +++ b/devices/airspy-handler/libairspy/iqconverter_int16.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 2014, Youssef Touil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef IQCONVERTER_INT16_H +#define IQCONVERTER_INT16_H + +#include + +typedef struct { + int len; + int fir_index; + int delay_index; + int16_t old_x; + int16_t old_y; + int32_t old_e; + int32_t *fir_kernel; + int32_t *fir_queue; + int16_t *delay_line; +} iqconverter_int16_t; + +iqconverter_int16_t *iqconverter_int16_create(const int16_t *hb_kernel, int len); +void iqconverter_int16_free(iqconverter_int16_t *cnv); +void iqconverter_int16_reset(iqconverter_int16_t *cnv); +void iqconverter_int16_process(iqconverter_int16_t *cnv, int16_t *samples, int len); + +#endif // IQCONVERTER_INT16_H diff --git a/qt-1090.cpp b/qt-1090.cpp index 09ea9d8..cd5260a 100755 --- a/qt-1090.cpp +++ b/qt-1090.cpp @@ -39,12 +39,12 @@ #include "xclose.h" #include "device-handler.h" -#ifdef __HAVE_RTLTCP__ -#include "rtl_tcp-handler.h" -#endif #ifdef __HAVE_RTLSDR__ #include "rtlsdr-handler.h" #endif +#ifdef __HAVE_AIRSPY__ +#include "airspy-handler.h" +#endif #ifdef __HAVE_SDRPLAY_V2 #include "sdrplay-handler-v2.h" #endif @@ -60,6 +60,9 @@ #ifdef __HAVE_LIME__ #include "lime-handler.h" #endif +#ifdef __HAVE_RTLTCP__ +#include "rtl_tcp-handler.h" +#endif #include "file-handler.h" static @@ -81,12 +84,12 @@ int i; httpPort = qt1090Settings -> value ("http_port", 8080). toInt (); bitstoShow = qt1090Settings -> value ("bitstoShow", 16). toInt (); -#ifdef __HAVE_RTLTCP__ - deviceSelector -> addItem ("rtl_tcp"); -#endif #ifdef __HAVE_RTLSDR__ deviceSelector -> addItem ("rtlsdr"); #endif +#ifdef __HAVE_AIRSPY__ + deviceSelector -> addItem ("airspy"); +#endif #ifdef __HAVE_SDRPLAY_V2 deviceSelector -> addItem ("sdrplay-v2"); #endif @@ -102,6 +105,9 @@ int i; #ifdef __HAVE_LIME__ deviceSelector -> addItem ("lime"); #endif +#ifdef __HAVE_RTLTCP__ + deviceSelector -> addItem ("rtl_tcp"); +#endif //#include "file-handler.h" for (i = 0; i < 31; i ++) @@ -741,6 +747,17 @@ theDevice = nullptr; } else #endif +#ifdef __HAVE_AIRSPY__ + if (device == "airspy") { + try { + theDevice = new airspyHandler (qt1090Settings, this -> frequency); + } catch (int e) { + fprintf (stderr, "no airspy device detected, try again\n"); + return; + } + } + else +#endif #ifdef __HAVE_PLUTO__ if (device == "pluto") { try { diff --git a/qt-1090.pro b/qt-1090.pro index 0bb270a..3e3b1df 100755 --- a/qt-1090.pro +++ b/qt-1090.pro @@ -24,6 +24,7 @@ RESOURCES += resources.qrc CONFIG += sdrplay-v2 CONFIG += sdrplay-v3 CONFIG += dabstick +CONFIG += airspy CONFIG += pluto CONFIG += lime CONFIG += hackrf @@ -128,6 +129,19 @@ dabstick { ./devices/rtlsdr-handler/rtl-dongleselect.cpp } # +# airspy +# +airspy { + DEFINES += __HAVE_AIRSPY__ + FORMS += ./devices/airspy-handler/airspy-widget.ui + INCLUDEPATH += ./devices/airspy-handler + INCLUDEPATH += ./devices/airspy-handler/libairspy + DEPENDPATH += ./devices/airspy-handler + DEPENDPATH += ./devices/airspy-handler/libairspy + HEADERS += ./devices/airspy-handler/airspy-handler.h + SOURCES += ./devices/airspy-handler/airspy-handler.cpp +} +# # the SDRplay # sdrplay-v2 {