Quisk version 4.2.28
This commit is contained in:
@@ -0,0 +1 @@
|
||||
#
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
soapy2:
|
||||
python2 setup.py build_ext --force --inplace
|
||||
|
||||
soapy3:
|
||||
python3 setup.py build_ext --force --inplace
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
# This is the hardware file to support radios accessed by the SoapySDR interface.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import socket, traceback, time, math
|
||||
import _quisk as QS
|
||||
try:
|
||||
from soapypkg import soapy
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
soapy = None
|
||||
|
||||
from quisk_hardware_model import Hardware as BaseHardware
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
class Hardware(BaseHardware):
|
||||
def __init__(self, app, conf):
|
||||
BaseHardware.__init__(self, app, conf)
|
||||
self.vardecim_index = 0
|
||||
self.fVFO = 0.0 # Careful, this is a float
|
||||
def pre_open(self):
|
||||
pass
|
||||
def set_parameter(self, *args):
|
||||
if soapy:
|
||||
txt = soapy.set_parameter(*args)
|
||||
if txt:
|
||||
dlg = wx.MessageDialog(None, txt, 'SoapySDR Error', wx.OK|wx.ICON_ERROR)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
def open(self): # Called once to open the Hardware
|
||||
if not soapy:
|
||||
return "Soapy module not available"
|
||||
radio_dict = self.application.local_conf.GetRadioDict()
|
||||
device = radio_dict.get('soapy_device', '')
|
||||
if radio_dict.get('soapy_enable_tx', '') == "Enable":
|
||||
txt = soapy.open_device(device, 1, self.conf.data_poll_usec)
|
||||
else:
|
||||
txt = soapy.open_device(device, 3, self.conf.data_poll_usec) # Tx is disabled
|
||||
for name in ('soapy_setAntenna_rx', 'soapy_setAntenna_tx'):
|
||||
value = radio_dict.get(name, '') # string values
|
||||
self.set_parameter(name, value, 0.0)
|
||||
for name in ('soapy_setBandwidth_rx', 'soapy_setBandwidth_tx', 'soapy_setSampleRate_rx', 'soapy_setSampleRate_tx'):
|
||||
value = radio_dict.get(name, '')
|
||||
try:
|
||||
value = float(value) * 1E3 # these are in KHz
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.set_parameter(name, '', value)
|
||||
if name == 'soapy_setSampleRate_tx':
|
||||
value = int(value + 0.1)
|
||||
QS.set_tx_audio(tx_sample_rate=value)
|
||||
self.ChangeGain('_rx')
|
||||
self.ChangeGain('_tx')
|
||||
#for name in ('soapy_getSampleRate_rx', 'soapy_getSampleRate_tx', 'soapy_getBandwidth_rx', 'soapy_getBandwidth_tx'):
|
||||
# print ('Get ***', name, soapy.get_parameter(name, 1))
|
||||
return txt
|
||||
def ChangeGain(self, rxtx): # rxtx is '_rx' or '_tx'
|
||||
if not soapy:
|
||||
return
|
||||
radio_dict = self.application.local_conf.GetRadioDict()
|
||||
gain_mode = radio_dict['soapy_gain_mode' + rxtx]
|
||||
gain_values = radio_dict['soapy_gain_values' + rxtx]
|
||||
if gain_mode == 'automatic':
|
||||
self.set_parameter('soapy_setGainMode' + rxtx, 'true', 0.0)
|
||||
elif gain_mode == 'total':
|
||||
self.set_parameter('soapy_setGainMode' + rxtx, 'false', 0.0)
|
||||
gain = gain_values.get('total', '0')
|
||||
gain = float(gain)
|
||||
self.set_parameter('soapy_setGain' + rxtx, '', gain)
|
||||
elif gain_mode == 'detailed':
|
||||
self.set_parameter('soapy_setGainMode' + rxtx, 'false', 0.0)
|
||||
for name, dmin, dmax, dstep in radio_dict.get('soapy_listGainsValues' + rxtx, ()):
|
||||
if name == 'total':
|
||||
continue
|
||||
gain = gain_values.get(name, '0')
|
||||
gain = float(gain)
|
||||
self.set_parameter('soapy_setGainElement' + rxtx, name, gain)
|
||||
def close(self): # Called once to close the Hardware
|
||||
if soapy:
|
||||
soapy.close_device(1)
|
||||
def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
|
||||
fVFO = float(vfo - self.transverter_offset)
|
||||
if self.fVFO != fVFO:
|
||||
self.fVFO = fVFO
|
||||
self.set_parameter('soapy_setFrequency_rx', '', fVFO)
|
||||
self.set_parameter('soapy_setFrequency_tx', '', float(tune - self.transverter_offset))
|
||||
return tune, vfo
|
||||
def ReturnFrequency(self):
|
||||
# Return the current tuning and VFO frequency. If neither have changed,
|
||||
# you can return (None, None). This is called at about 10 Hz by the main.
|
||||
# return (tune, vfo) # return changed frequencies
|
||||
return None, None # frequencies have not changed
|
||||
def ReturnVfoFloat(self):
|
||||
# Return the accurate VFO frequency as a floating point number.
|
||||
# You can return None to indicate that the integer VFO frequency is valid.
|
||||
return None
|
||||
def OnBtnFDX(self, fdx): # fdx is 0 or 1
|
||||
if soapy:
|
||||
self.set_parameter('soapy_FDX', '', float(fdx))
|
||||
def OnButtonPTT(self, event):
|
||||
btn = event.GetEventObject()
|
||||
if btn.GetValue():
|
||||
QS.set_PTT(1)
|
||||
QS.set_key_down(1)
|
||||
else:
|
||||
QS.set_PTT(0)
|
||||
QS.set_key_down(0)
|
||||
def OnSpot(self, level):
|
||||
# level is -1 for Spot button Off; else the Spot level 0 to 1000.
|
||||
pass
|
||||
def ChangeMode(self, mode): # Change the tx/rx mode
|
||||
# mode is a string: "USB", "AM", etc.
|
||||
pass
|
||||
def ChangeBand(self, band):
|
||||
# band is a string: "60", "40", "WWV", etc.
|
||||
BaseHardware.ChangeBand(self, band)
|
||||
def HeartBeat(self): # Called at about 10 Hz by the main
|
||||
pass
|
||||
def ImmediateChange(self, name, value):
|
||||
if name in ('soapy_gain_mode_rx', 'soapy_gain_mode_tx'):
|
||||
self.ChangeGain(name[-3:])
|
||||
elif name in ('soapy_setAntenna_rx', 'soapy_setAntenna_tx'):
|
||||
self.set_parameter(name, value, 0.0) # string values
|
||||
elif name in ('soapy_setBandwidth_rx', 'soapy_setBandwidth_tx', 'soapy_setSampleRate_rx', 'soapy_setSampleRate_tx'):
|
||||
try:
|
||||
value = float(value) * 1E3 # kHz values
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
self.set_parameter(name, '', value)
|
||||
if name == 'soapy_setSampleRate_tx':
|
||||
value = int(value + 0.1)
|
||||
QS.set_tx_audio(tx_sample_rate=value)
|
||||
elif name == 'soapy_setSampleRate_rx':
|
||||
value = int(value + 0.1)
|
||||
self.application.OnBtnDecimation(rate=value)
|
||||
self.set_parameter('soapy_setFrequency_rx', '', self.fVFO) # driver Lime requires reset of Rx freq on sample rate change
|
||||
# The "VarDecim" methods are used to change the hardware decimation rate.
|
||||
# If VarDecimGetChoices() returns any False value, no other methods are called.
|
||||
def VarDecimGetChoices(self): # Not used to set sample rate
|
||||
return ["None"]
|
||||
def VarDecimGetLabel(self): # Return a text label for the decimation control.
|
||||
return 'Rx rate: Use SoapySDR config'
|
||||
def VarDecimGetIndex(self): # Return the index 0, 1, ... of the current decimation.
|
||||
return 0
|
||||
def VarDecimSet(self, index=None): # Called when the control is operated; if index==None, called on startup.
|
||||
name = 'soapy_setSampleRate_rx'
|
||||
radio_dict = self.application.local_conf.GetRadioDict()
|
||||
rate = radio_dict.get(name, 48) # this is in KHz
|
||||
try:
|
||||
rate = float(rate) * 1E3
|
||||
rate = int(rate + 0.1)
|
||||
except:
|
||||
rate = 48000
|
||||
return rate
|
||||
def VarDecimRange(self): # Return the lowest and highest sample rate.
|
||||
return 48000, 192000
|
||||
@@ -0,0 +1,50 @@
|
||||
from distutils.core import setup, Extension
|
||||
import sys
|
||||
|
||||
module2 = Extension ('soapy',
|
||||
libraries = ['m', 'SoapySDR'],
|
||||
sources = ['../import_quisk_api.c', 'soapy.c'],
|
||||
include_dirs = ['.', '..'],
|
||||
)
|
||||
|
||||
modulew2 = Extension ('soapy',
|
||||
sources = ['../import_quisk_api.c', 'soapy.c'],
|
||||
include_dirs = ['.', '..'],
|
||||
libraries = ['WS2_32', 'SoapySDR'],
|
||||
)
|
||||
|
||||
if sys.platform == "win32":
|
||||
Modules = [modulew2]
|
||||
else:
|
||||
Modules = [module2]
|
||||
|
||||
setup (name = 'soapy',
|
||||
version = '0.1',
|
||||
description = 'soapy is an extension to Quisk to support hardware using the SoapySDR API',
|
||||
long_description = """SoapySDR is a layer of software that can connect to various SDR
|
||||
hardware. It provides a standard API to a client program. By using the SoapySDR API, Quisk can
|
||||
connect to all the hardware devices that SoapySDR supports.
|
||||
""",
|
||||
author = 'James C. Ahlstrom',
|
||||
author_email = 'jahlstr@gmail.com',
|
||||
url = 'http://james.ahlstrom.name/quisk/soapy.html',
|
||||
download_url = 'http://james.ahlstrom.name/quisk/',
|
||||
packages = ['quisk.soapypkg'],
|
||||
package_dir = {'soapy' : '.'},
|
||||
ext_modules = Modules,
|
||||
classifiers = [
|
||||
'Development Status :: 6 - Mature',
|
||||
'Environment :: X11 Applications',
|
||||
'Environment :: Win32 (MS Windows)',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'License :: OSI Approved :: GNU General Public License (GPL)',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: C',
|
||||
'Topic :: Communications :: Ham Radio',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
#include <Python.h>
|
||||
#include <complex.h>
|
||||
#include <SoapySDR/Device.h>
|
||||
#include <SoapySDR/Formats.h>
|
||||
#include <SoapySDR/Version.h>
|
||||
|
||||
#define IMPORT_QUISK_API
|
||||
#include "quisk.h"
|
||||
#include "filter.h"
|
||||
|
||||
// This module was written by James Ahlstrom, N2ADR.
|
||||
|
||||
// This module uses the Python interface to import symbols from the parent _quisk
|
||||
// extension module. It must be linked with import_quisk_api.c. See the documentation
|
||||
// at the start of import_quisk_api.c.
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#define RX_BUF_SIZE (SAMP_BUFFER_SIZE / 2)
|
||||
static SoapySDRDevice * soapy_sample_device; // device for the sample stream
|
||||
static SoapySDRDevice * soapy_config_device; // device for configuration, not samples
|
||||
static SoapySDRStream * rxStream;
|
||||
static SoapySDRStream * txStream;
|
||||
static double rx_sample_rate = 48000;
|
||||
static double tx_sample_rate = 48000;
|
||||
static complex float rx_stream_buffer[RX_BUF_SIZE];
|
||||
static void * rx_stream_buffs[] = {rx_stream_buffer};
|
||||
static int shutdown_sample_device;
|
||||
static int data_poll_usec = 10000;
|
||||
static int soapy_FDX; // Full duplex flag
|
||||
static int soapy_KeyDown; // Current key state
|
||||
static int soapy_KeyWasDown; // Previous key state
|
||||
static size_t numTxChannels; // number of Tx channels
|
||||
static size_t txMTU; // maximum transmission unit of Tx stream
|
||||
|
||||
// Start sample capture; called from the sound thread.
|
||||
static void quisk_start_samples(void)
|
||||
{
|
||||
//setup an Rx and Tx stream (complex floats)
|
||||
#if SOAPY_SDR_API_VERSION < 0x00080000
|
||||
if (SoapySDRDevice_setupStream(soapy_sample_device, &rxStream, SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
|
||||
printf("Soapy Rx setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return;
|
||||
}
|
||||
if (numTxChannels) {
|
||||
if (SoapySDRDevice_setupStream(soapy_sample_device, &txStream, SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
|
||||
printf("Soapy Tx setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return;
|
||||
}
|
||||
txMTU = SoapySDRDevice_getStreamMTU(soapy_sample_device, txStream);
|
||||
}
|
||||
#else
|
||||
if ((rxStream = SoapySDRDevice_setupStream(soapy_sample_device, SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL)) == NULL) {
|
||||
printf("Soapy Rx setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return;
|
||||
}
|
||||
if (numTxChannels) {
|
||||
if ((txStream = SoapySDRDevice_setupStream(soapy_sample_device, SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL)) == NULL) {
|
||||
printf("Soapy Tx setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return;
|
||||
}
|
||||
txMTU = SoapySDRDevice_getStreamMTU(soapy_sample_device, txStream);
|
||||
}
|
||||
#endif
|
||||
SoapySDRDevice_activateStream(soapy_sample_device, rxStream, 0, 0, 0); //start streaming
|
||||
}
|
||||
|
||||
// Stop sample capture; called from the sound thread.
|
||||
static void quisk_stop_samples(void)
|
||||
{
|
||||
shutdown_sample_device = 1;
|
||||
if (rxStream) {
|
||||
SoapySDRDevice_deactivateStream(soapy_sample_device, rxStream, 0, 0); //stop streaming
|
||||
SoapySDRDevice_closeStream(soapy_sample_device, rxStream);
|
||||
rxStream = NULL;
|
||||
}
|
||||
if (txStream) {
|
||||
SoapySDRDevice_deactivateStream(soapy_sample_device, txStream, 0, 0); //stop streaming
|
||||
SoapySDRDevice_closeStream(soapy_sample_device, txStream);
|
||||
txStream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Called in a loop to read samples; called from the sound thread.
|
||||
static int quisk_read_samples(complex double * cSamples)
|
||||
{
|
||||
int i, flags; //flags set by receive operation
|
||||
long long timeNs; //timestamp for receive buffer
|
||||
int nSamples;
|
||||
int num_samp;
|
||||
|
||||
soapy_KeyDown = quisk_is_key_down();
|
||||
num_samp = (int)(rx_sample_rate * (data_poll_usec * 1E-6));
|
||||
num_samp = ((num_samp + 255) / 256) * 256;
|
||||
if (num_samp > RX_BUF_SIZE)
|
||||
num_samp = RX_BUF_SIZE;
|
||||
if (shutdown_sample_device) {
|
||||
if (rxStream) {
|
||||
quisk_stop_samples();
|
||||
}
|
||||
if (soapy_sample_device) {
|
||||
SoapySDRDevice_unmake(soapy_sample_device);
|
||||
soapy_sample_device = NULL;
|
||||
}
|
||||
nSamples = num_samp;
|
||||
for (i = 0; i < nSamples; i++)
|
||||
cSamples[i] = 0;
|
||||
}
|
||||
else if (rxStream) {
|
||||
nSamples = SoapySDRDevice_readStream(soapy_sample_device, rxStream, rx_stream_buffs, num_samp, &flags, &timeNs, data_poll_usec * 2);
|
||||
if (nSamples == -1) { // Timeout
|
||||
nSamples = 0;
|
||||
}
|
||||
else if (nSamples < 0) { // Some other error
|
||||
pt_quisk_sound_state->read_error++;
|
||||
nSamples = 0;
|
||||
}
|
||||
pt_quisk_sound_state->latencyCapt = 0;
|
||||
for (i = 0; i < nSamples; i++)
|
||||
cSamples[i] = rx_stream_buffer[i] * CLIP32;
|
||||
}
|
||||
else {
|
||||
nSamples = num_samp;
|
||||
for (i = 0; i < nSamples; i++)
|
||||
cSamples[i] = 0;
|
||||
}
|
||||
return nSamples; // return number of samples
|
||||
}
|
||||
|
||||
// Called in a loop to write samples; called from the sound thread.
|
||||
static int quisk_write_samples(complex double * cSamples, int nSamples)
|
||||
{
|
||||
static complex float * tx_stream_buffer = NULL;
|
||||
static int tx_buf_size = 0;
|
||||
static long long timeNs = 0;
|
||||
int i, flags, ret, count;
|
||||
|
||||
if ( ! txStream)
|
||||
return 0;
|
||||
if (soapy_KeyDown != soapy_KeyWasDown) { // key changed state
|
||||
soapy_KeyWasDown = soapy_KeyDown;
|
||||
if (DEBUG)
|
||||
printf("**** Key Change %i rate %.0f\n", soapy_KeyDown, tx_sample_rate);
|
||||
if (soapy_KeyDown) // Key went down
|
||||
SoapySDRDevice_activateStream(soapy_sample_device, txStream, 0, 0, 0); // start Tx streaming
|
||||
else // Key went up
|
||||
SoapySDRDevice_deactivateStream(soapy_sample_device, txStream, 0, 0); // stop Tx streaming
|
||||
}
|
||||
if ( ! soapy_KeyDown || nSamples <= 0)
|
||||
return 0;
|
||||
|
||||
if (tx_buf_size < nSamples) {
|
||||
if (tx_stream_buffer)
|
||||
free(tx_stream_buffer);
|
||||
tx_buf_size = nSamples * 2;
|
||||
tx_stream_buffer = (complex float *)malloc(tx_buf_size * sizeof(complex float));
|
||||
}
|
||||
for (i = 0; i < nSamples; i++)
|
||||
tx_stream_buffer[i] = cSamples[i] / CLIP16;
|
||||
while (nSamples > 0) {
|
||||
if (nSamples > (int)txMTU)
|
||||
count = txMTU;
|
||||
else
|
||||
count = nSamples;
|
||||
nSamples -= count;
|
||||
timeNs = 0; //+= count / tx_sample_rate * 1E9;
|
||||
ret = SoapySDRDevice_writeStream(soapy_sample_device, txStream, (void *)&tx_stream_buffer, count, &flags, timeNs, data_poll_usec * 2);
|
||||
if (ret < 0)
|
||||
printf("Soapy writeStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
if (ret != count)
|
||||
printf ("Soapy writeStream short write; %d < %d\n", ret, count);
|
||||
//printf ("Soapy writeStream write; %i %i\n", ret, count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called to close the sample source; called from the GUI thread.
|
||||
static PyObject * close_device(PyObject * self, PyObject * args)
|
||||
{
|
||||
int sample_device;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", &sample_device))
|
||||
return NULL;
|
||||
if (sample_device) {
|
||||
shutdown_sample_device = 1;
|
||||
}
|
||||
else {
|
||||
if (soapy_config_device) {
|
||||
SoapySDRDevice_unmake(soapy_config_device);
|
||||
soapy_config_device = NULL;
|
||||
}
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// Called to open the SoapySDR device; called from the GUI thread.
|
||||
static PyObject * open_device(PyObject * self, PyObject * args)
|
||||
{
|
||||
int sample_device, poll;
|
||||
const char * name;
|
||||
char buf128[128];
|
||||
SoapySDRDevice * sdev;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "sii", &name, &sample_device, &poll))
|
||||
return NULL;
|
||||
sdev = SoapySDRDevice_makeStrArgs(name);
|
||||
if(sdev) {
|
||||
snprintf(buf128, 128, "Capture from %s", name);
|
||||
if (sample_device) {
|
||||
shutdown_sample_device = 0;
|
||||
soapy_sample_device = sdev;
|
||||
data_poll_usec = poll;
|
||||
quisk_sample_source4(&quisk_start_samples, &quisk_stop_samples, &quisk_read_samples, &quisk_write_samples);
|
||||
numTxChannels = SoapySDRDevice_getNumChannels(sdev, SOAPY_SDR_TX);
|
||||
if (sample_device == 3) // disable transmit
|
||||
numTxChannels = 0;
|
||||
}
|
||||
else {
|
||||
soapy_config_device = sdev;
|
||||
}
|
||||
}
|
||||
else {
|
||||
snprintf(buf128, 128, "SoapySDRDevice_make fail: %s", SoapySDRDevice_lastError());
|
||||
}
|
||||
return PyString_FromString(buf128);
|
||||
}
|
||||
|
||||
static void get_direc_len(const char * name, int * direction, int * length)
|
||||
{ // return the direction (Rx or Tx) and length of name to compare
|
||||
*length = strlen(name);
|
||||
*direction = SOAPY_SDR_RX;
|
||||
if (*length < 4)
|
||||
return;
|
||||
if (name[*length - 1] == 'x' && name[*length - 3] == '_') { // ends in "_rx" or "_tx"
|
||||
if (name[*length - 2] == 't')
|
||||
*direction = SOAPY_SDR_TX;
|
||||
*length -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of SoapySDR devices
|
||||
static PyObject * get_device_list(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{
|
||||
PyObject * devices;
|
||||
PyObject * dict;
|
||||
size_t length, i, j;
|
||||
SoapySDRKwargs * results;
|
||||
|
||||
if (!PyArg_ParseTuple (args, ""))
|
||||
return NULL;
|
||||
devices = PyList_New(0);
|
||||
results = SoapySDRDevice_enumerate(NULL, &length);
|
||||
for (i = 0; i < length; i++) {
|
||||
dict = PyDict_New();
|
||||
for (j = 0; j < results[i].size; j++)
|
||||
PyDict_SetItemString(dict, results[i].keys[j], PyString_FromString(results[i].vals[j]));
|
||||
PyList_Append(devices, dict);
|
||||
Py_DECREF(dict);
|
||||
}
|
||||
SoapySDRKwargsList_clear(results, length);
|
||||
return devices;
|
||||
}
|
||||
|
||||
static PyObject * set_parameter(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{ // Parameter name can end in "_rx" or "_tx" to specify direction.
|
||||
int direction, length;
|
||||
const char * param; // name of the parameter
|
||||
const char * name2; // string data or sub-parameter name if any
|
||||
double datum; // floating point value if any
|
||||
bool is_true;
|
||||
char msg200[200];
|
||||
|
||||
if (!PyArg_ParseTuple (args, "ssd", ¶m, &name2, &datum))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
printf ("Set %s - %s - %lf\n", param, name2, datum);
|
||||
get_direc_len(param, &direction, &length);
|
||||
msg200[0] = 0;
|
||||
if (soapy_sample_device) {
|
||||
if (numTxChannels <= 0 && direction == SOAPY_SDR_TX) {
|
||||
}
|
||||
//else if (direction == SOAPY_SDR_TX) {
|
||||
//}
|
||||
else if ( ! strcmp(param, "soapy_FDX")) {
|
||||
if (datum)
|
||||
soapy_FDX = 1;
|
||||
else
|
||||
soapy_FDX = 0;
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setAntenna", length)) { // do not set empty string
|
||||
if (name2[0] && SoapySDRDevice_setAntenna(soapy_sample_device, direction, 0, name2) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setBandwidth", length)) {
|
||||
if (soapy_sample_device && SoapySDRDevice_setBandwidth(soapy_sample_device, direction, 0, datum) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setFrequency", length)) {
|
||||
if (SoapySDRDevice_setFrequency(soapy_sample_device, direction, 0, datum, NULL) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setGain", length)) {
|
||||
if (soapy_sample_device && SoapySDRDevice_setGain(soapy_sample_device, direction, 0, datum) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setGainElement", length)) {
|
||||
if (SoapySDRDevice_setGainElement(soapy_sample_device, direction, 0, name2, datum) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setGainMode", length)) {
|
||||
if ( ! strcmp(name2, "true"))
|
||||
is_true = 1;
|
||||
else
|
||||
is_true = 0;
|
||||
if (SoapySDRDevice_setGainMode(soapy_sample_device, direction, 0, is_true) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else if ( ! strncmp(param, "soapy_setSampleRate", length)) {
|
||||
if (direction == SOAPY_SDR_RX)
|
||||
rx_sample_rate = datum;
|
||||
else
|
||||
tx_sample_rate = datum;
|
||||
if (SoapySDRDevice_setSampleRate(soapy_sample_device, direction, 0, datum) != 0)
|
||||
snprintf(msg200, 200, "%s fail: %s\n", param, SoapySDRDevice_lastError());
|
||||
}
|
||||
else {
|
||||
snprintf(msg200, 200, "Soapy set_parameter() for unknown name %s\n", param);
|
||||
}
|
||||
}
|
||||
if (msg200[0])
|
||||
return PyString_FromString(msg200);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static void Range2List(SoapySDRRange range, PyObject * pylist)
|
||||
{
|
||||
PyObject * pyobj;
|
||||
|
||||
pyobj = PyFloat_FromDouble(range.minimum);
|
||||
PyList_Append(pylist, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
pyobj = PyFloat_FromDouble(range.maximum);
|
||||
PyList_Append(pylist, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
pyobj = PyFloat_FromDouble(range.step);
|
||||
PyList_Append(pylist, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
}
|
||||
|
||||
static PyObject * get_parameter(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{ // Return a SoapySDR parameter.
|
||||
// Parameter name can end in "_rx" or "_tx" to specify direction.
|
||||
int sample_device, direction, length;
|
||||
char * name;
|
||||
char ** names;
|
||||
size_t i, len_list;
|
||||
bool is_true;
|
||||
double value;
|
||||
PyObject * pylist, * pyobj, * pylst2;
|
||||
SoapySDRDevice * sdev;
|
||||
SoapySDRRange range;
|
||||
SoapySDRRange * ranges;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "si", &name, &sample_device))
|
||||
return NULL;
|
||||
if (sample_device)
|
||||
sdev = soapy_sample_device;
|
||||
else
|
||||
sdev = soapy_config_device;
|
||||
get_direc_len(name, &direction, &length);
|
||||
if ( ! sdev) {
|
||||
;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_listAntennas", length)) {
|
||||
pylist = PyList_New(0);
|
||||
names = SoapySDRDevice_listAntennas(sdev, direction, 0, &len_list);
|
||||
for (i = 0; i < len_list; i++) {
|
||||
pyobj = PyString_FromString(names[i]);
|
||||
PyList_Append(pylist, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
}
|
||||
SoapySDRStrings_clear(&names, len_list);
|
||||
return pylist;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getBandwidth", length)) {
|
||||
value = SoapySDRDevice_getBandwidth(sdev, direction, 0);
|
||||
return PyFloat_FromDouble(value);
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getBandwidthRange", length)) {
|
||||
pylist = PyList_New(0);
|
||||
ranges = SoapySDRDevice_getBandwidthRange(sdev, direction, 0, &len_list);
|
||||
for (i = 0; i < len_list; i++) {
|
||||
pylst2 = PyList_New(0);
|
||||
range = ranges[i];
|
||||
Range2List(range, pylst2);
|
||||
PyList_Append(pylist, pylst2);
|
||||
Py_DECREF(pylst2);
|
||||
}
|
||||
return pylist;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getFullDuplex", length)) {
|
||||
is_true = SoapySDRDevice_getFullDuplex(sdev, direction, 0);
|
||||
if (is_true)
|
||||
return PyInt_FromLong(1);
|
||||
else
|
||||
return PyInt_FromLong(0);
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getGainRange", length)) {
|
||||
pylist = PyList_New(0);
|
||||
range = SoapySDRDevice_getGainRange(sdev, direction, 0);
|
||||
Range2List(range, pylist);
|
||||
return pylist;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getSampleRate", length)) {
|
||||
value = SoapySDRDevice_getSampleRate(sdev, direction, 0);
|
||||
return PyFloat_FromDouble(value);
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_getSampleRateRange", length)) {
|
||||
pylist = PyList_New(0);
|
||||
ranges = SoapySDRDevice_getSampleRateRange(sdev, direction, 0, &len_list);
|
||||
for (i = 0; i < len_list; i++) {
|
||||
pylst2 = PyList_New(0);
|
||||
range = ranges[i];
|
||||
Range2List(range, pylst2);
|
||||
PyList_Append(pylist, pylst2);
|
||||
Py_DECREF(pylst2);
|
||||
}
|
||||
return pylist;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_hasGainMode", length)) {
|
||||
is_true = SoapySDRDevice_hasGainMode(sdev, direction, 0);
|
||||
if (is_true)
|
||||
return PyInt_FromLong(1);
|
||||
else
|
||||
return PyInt_FromLong(0);
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_listGains", length)) {
|
||||
pylist = PyList_New(0);
|
||||
names = SoapySDRDevice_listGains(sdev, direction, 0, &len_list);
|
||||
for (i = 0; i < len_list; i++) {
|
||||
pyobj = PyString_FromString(names[i]);
|
||||
PyList_Append(pylist, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
}
|
||||
SoapySDRStrings_clear(&names, len_list);
|
||||
return pylist;
|
||||
}
|
||||
else if ( ! strncmp(name, "soapy_listGainsValues", length)) {
|
||||
pylist = PyList_New(0);
|
||||
pylst2 = PyList_New(0); // First element is the total gain
|
||||
pyobj = PyString_FromString("total");
|
||||
PyList_Append(pylst2, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
range = SoapySDRDevice_getGainRange(sdev, direction, 0);
|
||||
Range2List(range, pylst2);
|
||||
PyList_Append(pylist, pylst2);
|
||||
Py_DECREF(pylst2);
|
||||
names = SoapySDRDevice_listGains(sdev, direction, 0, &len_list);
|
||||
for (i = 0; i < len_list; i++) {
|
||||
pylst2 = PyList_New(0);
|
||||
pyobj = PyString_FromString(names[i]);
|
||||
PyList_Append(pylst2, pyobj);
|
||||
Py_DECREF(pyobj);
|
||||
range = SoapySDRDevice_getGainElementRange(sdev, direction, 0, names[i]);
|
||||
Range2List(range, pylst2);
|
||||
PyList_Append(pylist, pylst2);
|
||||
Py_DECREF(pylst2);
|
||||
}
|
||||
SoapySDRStrings_clear(&names, len_list);
|
||||
return pylist;
|
||||
}
|
||||
else {
|
||||
printf("Soapy get_parameter() for unknown name %s\n", name);
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// Functions callable from Python are listed here:
|
||||
static PyMethodDef QuiskMethods[] = {
|
||||
{"open_device", open_device, METH_VARARGS, "Open the hardware."},
|
||||
{"close_device", close_device, METH_VARARGS, "Close the hardware"},
|
||||
{"get_device_list", get_device_list, METH_VARARGS, "Return a list of SoapySDR devices"},
|
||||
{"get_parameter", get_parameter, METH_VARARGS, "Get a SoapySDR parameter"},
|
||||
{"set_parameter", set_parameter, METH_VARARGS, "Set a SoapySDR parameter"},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
// Python 2.7:
|
||||
// Initialization, and registration of public symbol "initsoapy":
|
||||
PyMODINIT_FUNC initsoapy (void)
|
||||
{
|
||||
if (Py_InitModule ("soapy", QuiskMethods) == NULL) {
|
||||
printf("Py_InitModule failed!\n");
|
||||
return;
|
||||
}
|
||||
// Import pointers to functions and variables from module _quisk
|
||||
if (import_quisk_api()) {
|
||||
printf("Failure to import pointers from _quisk\n");
|
||||
return; //Error
|
||||
}
|
||||
}
|
||||
|
||||
// Python 3:
|
||||
#else
|
||||
static struct PyModuleDef soapymodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"soapy",
|
||||
NULL,
|
||||
-1,
|
||||
QuiskMethods
|
||||
} ;
|
||||
|
||||
PyMODINIT_FUNC PyInit_soapy(void)
|
||||
{
|
||||
PyObject * m;
|
||||
|
||||
m = PyModule_Create(&soapymodule);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
// Import pointers to functions and variables from module _quisk
|
||||
if (import_quisk_api()) {
|
||||
printf("Failure to import pointers from _quisk\n");
|
||||
return m; //Error
|
||||
}
|
||||
return m;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user