Quisk version 4.2.28
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
Microtelecom Perseus HF receiver
|
||||
|
||||
Prerequisite are:
|
||||
|
||||
libusb-1.0-0-dev (found in all major Linux distro)
|
||||
|
||||
libperseus-sdr as found in https://github.com/Microtelecom/libperseus-sdr/archive/master.zip
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
perseus2:
|
||||
python2 setup.py build_ext --force --inplace
|
||||
|
||||
perseus3:
|
||||
python3 setup.py build_ext --force --inplace
|
||||
|
||||
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
*
|
||||
* Microtelecom perseus HF receiver
|
||||
*
|
||||
* access module: exposes Python functions needed in quisk_hardware.py
|
||||
* to control hardware
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <complex.h>
|
||||
#include <perseus-sdr.h>
|
||||
|
||||
#define IMPORT_QUISK_API
|
||||
#include "quisk.h"
|
||||
#include "filter.h"
|
||||
|
||||
// This module was written by Andrea Montefusco IW0HDV.
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
int32_t i;
|
||||
int32_t q;
|
||||
} __attribute__((__packed__)) iq;
|
||||
struct {
|
||||
uint8_t i1;
|
||||
uint8_t i2;
|
||||
uint8_t i3;
|
||||
uint8_t i4;
|
||||
uint8_t q1;
|
||||
uint8_t q2;
|
||||
uint8_t q3;
|
||||
uint8_t q4;
|
||||
} __attribute__((__packed__)) ;
|
||||
} iq_sample;
|
||||
|
||||
|
||||
// buffer size for libperseus-sdr
|
||||
const static int nb = 6;
|
||||
const static int bs = 1024;
|
||||
|
||||
|
||||
// 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 1
|
||||
|
||||
static int num_perseus = 0;
|
||||
static perseus_descr *descr = 0;
|
||||
static int sr = 48000;
|
||||
static float freq = 7050000.0;
|
||||
static int adc_dither = 0;
|
||||
static int adc_preamp = 0;
|
||||
|
||||
static void quisk_stop_samples(void);
|
||||
|
||||
static const char *fname = "/tmp/quiskperseus";
|
||||
static int rfd = 0;
|
||||
static int wfd = 0;
|
||||
static int running = 0;
|
||||
static int wb_filter = 0;
|
||||
|
||||
// Called in a loop to read samples; called from the sound thread.
|
||||
static int quisk_read_samples(complex double * cSamples)
|
||||
{
|
||||
//fprintf (stderr, "r"); fflush(stderr);
|
||||
|
||||
int n = read(rfd, cSamples, sizeof(complex double)*SAMP_BUFFER_SIZE);
|
||||
//fprintf(stderr, "%d ", n);
|
||||
if (n >= 0)
|
||||
return n/sizeof(complex double); // return number of samples
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called in a loop to write samples; called from the sound thread.
|
||||
static int quisk_write_samples(complex double * cSamples, int nSamples)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// callback that writes in the output pipe IQ values as
|
||||
// complex floating point
|
||||
//
|
||||
static int user_data_callback_c_f(void *buf, int buf_size, void *extra)
|
||||
{
|
||||
// The buffer received contains 24-bit IQ samples (6 bytes per sample)
|
||||
// Here we save the received IQ samples as 32 bit
|
||||
// (msb aligned) integer IQ samples.
|
||||
|
||||
uint8_t *samplebuf = (uint8_t*)buf;
|
||||
int nSamples = buf_size/6;
|
||||
int k;
|
||||
iq_sample s;
|
||||
|
||||
// the 24 bit data is scaled to a 32bit value (so that the machine's
|
||||
// natural signed arithmetic will work)
|
||||
for (k=0; k < nSamples; k++) {
|
||||
s.i1 = s.q1 = 0;
|
||||
s.i2 = *samplebuf++;
|
||||
s.i3 = *samplebuf++;
|
||||
s.i4 = *samplebuf++;
|
||||
s.q2 = *samplebuf++;
|
||||
s.q3 = *samplebuf++;
|
||||
s.q4 = *samplebuf++;
|
||||
|
||||
// move I/Q to complex number
|
||||
complex double x = (double)(s.iq.i)*10 + (double)(s.iq.q)*10 * _Complex_I;
|
||||
if (wfd > 0) {
|
||||
int n = write(wfd, &x, sizeof(complex double));
|
||||
if (n<0 && ! -EAGAIN )
|
||||
fprintf(stderr, "perseus c: Can't write output file: %s, descriptor: %d\n", strerror(errno), wfd);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Start sample capture; called from the sound thread.
|
||||
static void quisk_start_samples(void)
|
||||
{
|
||||
if (DEBUG) { fprintf (stderr, "perseus c: quisk_start_samples\n"); fflush(stderr); }
|
||||
|
||||
int rc = mkfifo(fname, 0666);
|
||||
|
||||
if ((rc == -1) && (errno != EEXIST)) {
|
||||
perror("perseus c: Error creating the named pipe");
|
||||
}
|
||||
|
||||
rfd = open(fname, O_RDONLY|O_NONBLOCK);
|
||||
if (rfd < 0) {
|
||||
fprintf(stderr, "perseus c: Can't open read FIFO (%s)\n", strerror(errno));
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: read FIFO (%d)\n", rfd);
|
||||
}
|
||||
wfd = open(fname, O_WRONLY|O_NONBLOCK);
|
||||
if (wfd < 0) {
|
||||
fprintf(stderr, "perseus c: Can't open write FIFO (%s)\n", strerror(errno));
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: write FIFO (%d)\n", wfd);
|
||||
}
|
||||
if (perseus_set_sampling_rate(descr, sr) < 0) { // specify the sampling rate value in Samples/second
|
||||
fprintf(stderr, "perseus c: fpga configuration error: %s\n", perseus_errorstr());
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: sampling rate set to: %d\n", sr);
|
||||
|
||||
// Re-enable preselection filters (WB_MODE Off)
|
||||
perseus_set_ddc_center_freq(descr, freq, wb_filter);
|
||||
// start sampling ops
|
||||
if (perseus_start_async_input(descr, nb*bs, user_data_callback_c_f, 0)<0) {
|
||||
fprintf(stderr, "perseus c: start async input error: %s\n", perseus_errorstr());
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: start async input\n");
|
||||
}
|
||||
running = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop sample capture; called from the sound thread.
|
||||
static void quisk_stop_samples(void)
|
||||
{
|
||||
if (DEBUG) { fprintf (stderr, "perseus c: quisk_stop_samples\n"); fflush(stderr); }
|
||||
|
||||
// We stop the acquisition...
|
||||
if (DEBUG) fprintf(stderr, "perseus c: stopping async data acquisition...\n");
|
||||
perseus_stop_async_input(descr);
|
||||
running = 0;
|
||||
// clearing FIFO...
|
||||
close(rfd);
|
||||
close(wfd);
|
||||
unlink(fname);
|
||||
}
|
||||
|
||||
|
||||
// Called to close the sample source; called from the GUI thread.
|
||||
static PyObject * close_device(PyObject * self, PyObject * args)
|
||||
{
|
||||
if (DEBUG) fprintf (stderr, "perseus c: close_device\n");
|
||||
int sample_device; // for now one only Perseus can be managed
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", &sample_device))
|
||||
return NULL;
|
||||
|
||||
if (descr) {
|
||||
// We stop the acquisition...
|
||||
if (running) {
|
||||
perseus_stop_async_input(descr);
|
||||
running = 0;
|
||||
}
|
||||
perseus_close(descr);
|
||||
descr = 0;
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// Called to open the Perseus SDR device; called from the GUI thread.
|
||||
static PyObject * open_device(PyObject * self, PyObject * args)
|
||||
{
|
||||
char buf128[128] = "Capture Microtelecom Perseus HF receiver";
|
||||
eeprom_prodid prodid;
|
||||
|
||||
if (DEBUG) { fprintf (stderr, "perseus c: open device (%d)\n", num_perseus); fflush(stderr); }
|
||||
|
||||
// Check how many Perseus receivers are connected to the system
|
||||
if (num_perseus == 0) num_perseus = perseus_init();
|
||||
if (DEBUG) fprintf(stderr, "perseus c: %d Perseus receivers found\n",num_perseus);
|
||||
|
||||
if (num_perseus == 0) {
|
||||
sprintf(buf128, "No Perseus receivers detected\n");
|
||||
perseus_exit();
|
||||
goto main_cleanup;
|
||||
}
|
||||
|
||||
// Open the first one...
|
||||
if ((descr = perseus_open(0)) == NULL) {
|
||||
sprintf(buf128, "error: %s\n", perseus_errorstr());
|
||||
fprintf(stderr, "perseus c: open error: %s\n", perseus_errorstr());
|
||||
goto main_cleanup;
|
||||
}
|
||||
|
||||
// Download the standard firmware to the unit
|
||||
if (DEBUG) fprintf(stderr, "perseus c: Downloading firmware...\n");
|
||||
if (perseus_firmware_download(descr,NULL)<0) {
|
||||
sprintf(buf128, "perseus c: firmware download error: %s", perseus_errorstr());
|
||||
goto main_cleanup;
|
||||
}
|
||||
// Dump some information about the receiver (S/N and HW rev)
|
||||
if (perseus_is_preserie(descr, 0) == PERSEUS_SNNOTAVAILABLE) {
|
||||
fprintf(stderr, "perseus c: The device is a preserie unit");
|
||||
} else {
|
||||
if (perseus_get_product_id(descr,&prodid)<0) {
|
||||
fprintf(stderr, "perseus c: get product id error: %s", perseus_errorstr());
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
fprintf(stderr, "perseus c: Receiver S/N: %05d-%02hX%02hX-%02hX%02hX-%02hX%02hX - HW Release:%hd.%hd\n",
|
||||
(uint16_t) prodid.sn,
|
||||
(uint16_t) prodid.signature[5],
|
||||
(uint16_t) prodid.signature[4],
|
||||
(uint16_t) prodid.signature[3],
|
||||
(uint16_t) prodid.signature[2],
|
||||
(uint16_t) prodid.signature[1],
|
||||
(uint16_t) prodid.signature[0],
|
||||
(uint16_t) prodid.hwrel,
|
||||
(uint16_t) prodid.hwver);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Printing all sampling rates available .....
|
||||
{
|
||||
int buf[BUFSIZ];
|
||||
|
||||
if (perseus_get_sampling_rates (descr, buf, sizeof(buf)/sizeof(buf[0])) < 0) {
|
||||
fprintf(stderr, "perseus c: get sampling rates error: %s\n", perseus_errorstr());
|
||||
goto main_cleanup;
|
||||
} else {
|
||||
int i = 0;
|
||||
while (buf[i]) {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: #%d: sample rate: %d\n", i, buf[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the receiver for 2 MS/s operations
|
||||
if (DEBUG) fprintf(stderr, "perseus c: Configuring FPGA...\n");
|
||||
if (perseus_set_sampling_rate(descr, sr) < 0) { // specify the sampling rate value in Samples/second
|
||||
//if (perseus_set_sampling_rate_n(descr, 0)<0) // specify the sampling rate value as ordinal in the vector
|
||||
fprintf(stderr, "perseus c: fpga configuration error: %s\n", perseus_errorstr());
|
||||
goto main_cleanup;
|
||||
}
|
||||
|
||||
// ADC settings
|
||||
perseus_set_adc (descr, adc_dither, adc_preamp);
|
||||
|
||||
// Disable preselection filters (WB_MODE On)
|
||||
//perseus_set_ddc_center_freq(descr, freq, 0);
|
||||
//sleep(1);
|
||||
// Re-enable preselection filters (WB_MODE Off)
|
||||
perseus_set_ddc_center_freq(descr, freq, wb_filter);
|
||||
|
||||
quisk_sample_source4(&quisk_start_samples, &quisk_stop_samples, &quisk_read_samples, &quisk_write_samples);
|
||||
|
||||
if (DEBUG) { fprintf (stderr, "perseus c: quisk sample source callbacks established\n"); fflush(stderr); }
|
||||
goto exit_success;
|
||||
|
||||
|
||||
|
||||
main_cleanup:
|
||||
return PyString_FromString("ERROR");
|
||||
|
||||
exit_success:
|
||||
|
||||
return PyString_FromString(buf128);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static PyObject * set_frequency(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{
|
||||
float param;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "f", ¶m))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
fprintf (stderr, "perseus c: set DDC frequency %lf WB filter:%d\n", param, wb_filter);
|
||||
freq= param;
|
||||
if (descr) perseus_set_ddc_center_freq(descr, freq, wb_filter);
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject * set_input_filter(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{
|
||||
int param;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", ¶m))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
fprintf (stderr, "perseus c: set input filter %d\n", param);
|
||||
wb_filter = param;
|
||||
if (descr) perseus_set_ddc_center_freq(descr, freq, wb_filter);
|
||||
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject * set_sampling_rate(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{
|
||||
int param;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", ¶m))
|
||||
return NULL;
|
||||
|
||||
if (DEBUG) fprintf (stderr, "perseus c: Set sampling rate %d\n", param);
|
||||
if (param < 48000) sr = param * 1000;
|
||||
else sr = param;
|
||||
|
||||
if (descr) {
|
||||
if (running) {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: stop async input\n");
|
||||
perseus_stop_async_input(descr);
|
||||
}
|
||||
|
||||
// specify the sampling rate value in Samples/secon
|
||||
if (perseus_set_sampling_rate(descr, sr) < 0) {
|
||||
fprintf(stderr, "perseus c: fpga configuration error: %s\n", perseus_errorstr());
|
||||
}
|
||||
|
||||
if (running) {
|
||||
if (perseus_start_async_input(descr, nb*bs, user_data_callback_c_f, 0)<0) {
|
||||
fprintf(stderr, "perseus c: start async input error: %s\n", perseus_errorstr());
|
||||
} else {
|
||||
if (DEBUG) fprintf(stderr, "perseus c: start async input @%d\n", sr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "perseus c: trying to start async input with no device open\n");
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject * set_attenuator(PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{ int param;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", ¶m))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
fprintf (stderr, "perseus c: Set attenuator %d\n", param);
|
||||
|
||||
if (descr) {
|
||||
// specify the sampling rate value in Samples/secon
|
||||
if (perseus_set_attenuator_n(descr, (int)(param / -10)) < 0) {
|
||||
fprintf(stderr, "perseus c: fpga configuration error: %s\n", perseus_errorstr());
|
||||
}
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
// Enable ADC Dither, Disable ADC Preamp
|
||||
// perseus_set_adc(descr, true, false);
|
||||
|
||||
static PyObject * set_adc_dither (PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{ int dither_;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", &dither_))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
fprintf (stderr, "perseus c: Set ADC: dither %d\n", dither_);
|
||||
|
||||
adc_dither = dither_;
|
||||
if (descr) {
|
||||
// specify the ADC dithering
|
||||
if (perseus_set_adc(descr, adc_dither == 1, adc_preamp == 1) < 0) {
|
||||
fprintf(stderr, "perseus c: ADC configuration error: %s\n", perseus_errorstr());
|
||||
}
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject * set_adc_preamp (PyObject * self, PyObject * args) // Called from GUI thread
|
||||
{ int preamp_;
|
||||
|
||||
if (!PyArg_ParseTuple (args, "i", &preamp_))
|
||||
return NULL;
|
||||
if (DEBUG)
|
||||
fprintf (stderr, "perseus c: Set ADC: preamp: %d\n", preamp_);
|
||||
|
||||
adc_preamp = preamp_;
|
||||
if (descr) {
|
||||
// specify the sampling rate value in Samples/secon
|
||||
if (perseus_set_adc(descr, adc_dither == 1, adc_preamp == 1) < 0) {
|
||||
fprintf(stderr, "perseus c: ADC configuration error: %s\n", perseus_errorstr());
|
||||
}
|
||||
}
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject * deinit(PyObject * self, PyObject * args) // Called from dctor
|
||||
{
|
||||
perseus_exit();
|
||||
|
||||
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"},
|
||||
{"set_frequency", set_frequency, METH_VARARGS, "set frequency"},
|
||||
{"set_input_filter", set_input_filter, METH_VARARGS, "set input filter"},
|
||||
{"set_sampling_rate", set_sampling_rate, METH_VARARGS, "set sampling rate"},
|
||||
{"set_attenuator", set_attenuator, METH_VARARGS, "set attenuator"},
|
||||
{"set_adc_dither", set_adc_dither, METH_VARARGS, "set ADC dither"},
|
||||
{"set_adc_preamp", set_adc_preamp, METH_VARARGS, "set ADC preamplifier"},
|
||||
{"deinit", deinit, METH_VARARGS, "deinit"},
|
||||
// {"get_device_list", get_device_list, METH_VARARGS, "Return a list of Perseus SDR devices"},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
// Python 2.7:
|
||||
// Initialization, and registration of public symbol "initperseus":
|
||||
PyMODINIT_FUNC initperseus (void)
|
||||
{
|
||||
if (Py_InitModule ("perseus", QuiskMethods) == NULL) {
|
||||
fprintf(stderr, "perseus c: Py_InitModule failed!\n");
|
||||
return;
|
||||
}
|
||||
// Import pointers to functions and variables from module _quisk
|
||||
if (import_quisk_api()) {
|
||||
fprintf(stderr, "perseus c: Failure to import pointers from _quisk\n");
|
||||
return; //Error
|
||||
}
|
||||
}
|
||||
|
||||
// Python 3:
|
||||
#else
|
||||
static struct PyModuleDef perseusmodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"perseus",
|
||||
NULL,
|
||||
-1,
|
||||
QuiskMethods
|
||||
} ;
|
||||
|
||||
PyMODINIT_FUNC PyInit_perseus(void)
|
||||
{
|
||||
PyObject * m;
|
||||
|
||||
m = PyModule_Create(&perseusmodule);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
// Import pointers to functions and variables from module _quisk
|
||||
if (import_quisk_api()) {
|
||||
fprintf(stderr, "perseus c: Failure to import pointers from _quisk\n");
|
||||
return m; //Error
|
||||
}
|
||||
return m;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
# This is the hardware file to support radios accessed by the PerseusSDR 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 perseuspkg import perseus
|
||||
except:
|
||||
#traceback.print_exc()
|
||||
perseus = None
|
||||
print ("Error: Perseus package not found.\n")
|
||||
|
||||
from quisk_hardware_model import Hardware as BaseHardware
|
||||
|
||||
DEBUG = 1
|
||||
|
||||
# Define the name of the hardware and the items on the hardware screen (see quisk_conf_defaults.py):
|
||||
################ Receivers PerseusSDR, The PerseusSDR interface to multiple hardware SDRs.
|
||||
## hardware_file_name Hardware file path, rfile
|
||||
# This is the file that contains the control logic for each radio.
|
||||
#hardware_file_name = 'perseuspkg/quisk_hardware.py'
|
||||
|
||||
## widgets_file_name Widget file path, rfile
|
||||
# This optional file adds additional controls for the radio.
|
||||
#widgets_file_name = 'perseuspkg/quisk_widgets.py'
|
||||
|
||||
class Hardware(BaseHardware):
|
||||
def __init__(self, app, conf):
|
||||
BaseHardware.__init__(self, app, conf)
|
||||
|
||||
self.rf_gain_labels = ('RF +0', 'RF -10', 'RF -20', 'RF -30')
|
||||
self.antenna_labels = ('Wide Band', 'Band Filter')
|
||||
|
||||
self.vardecim_index = 0
|
||||
self.fVFO = 0.0 # Careful, this is a float
|
||||
if DEBUG: print ("__init__: %s" % conf)
|
||||
self.rates = [ 48000, \
|
||||
95000, \
|
||||
96000, \
|
||||
125000, \
|
||||
192000, \
|
||||
250000, \
|
||||
500000, \
|
||||
1000000, \
|
||||
1600000, \
|
||||
2000000 \
|
||||
]
|
||||
self.current_rate = 192000
|
||||
self.att = 0;
|
||||
self.wb = 0
|
||||
|
||||
def __del__(self):
|
||||
# try to clear hardware
|
||||
if perseus:
|
||||
perseus.close()
|
||||
perseus.deinit()
|
||||
|
||||
def get_hw (self):
|
||||
return perseus
|
||||
|
||||
def pre_open(self):
|
||||
if DEBUG: print ("pre_open")
|
||||
pass
|
||||
|
||||
def set_parameter(self, *args):
|
||||
pass
|
||||
|
||||
def open(self): # Called once to open the Hardware
|
||||
|
||||
if not perseus:
|
||||
return "Perseus module not available"
|
||||
|
||||
txt = perseus.open_device("perseus",2,3)
|
||||
if DEBUG: print ("perseus hardware: open")
|
||||
|
||||
return txt
|
||||
|
||||
def close(self): # Called once to close the Hardware
|
||||
if DEBUG: print ("perseus hardware: close")
|
||||
if perseus:
|
||||
perseus.close_device(1)
|
||||
|
||||
def ChangeGain(self, rxtx): # rxtx is '_rx' or '_tx'
|
||||
if not perseus:
|
||||
return
|
||||
if DEBUG: print ("perseus hardware: ChangeGain", rxtx)
|
||||
pass
|
||||
|
||||
def OnButtonRfGain(self, event):
|
||||
#btn = event.GetEventObject()
|
||||
n = event.GetEventObject().index
|
||||
self.att = n * -10
|
||||
if DEBUG: print ("perseus hardware: OnButtonRfGain: %d new attenuation: %d" % (n, self.att))
|
||||
perseus.set_attenuator (self.att)
|
||||
|
||||
def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
|
||||
fVFO = float(vfo)
|
||||
if self.fVFO != fVFO:
|
||||
self.fVFO = fVFO
|
||||
perseus.set_frequency(fVFO)
|
||||
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 self.fVFO
|
||||
|
||||
# def OnBtnFDX(self, fdx): # fdx is 0 or 1
|
||||
# pass
|
||||
#
|
||||
# def OnButtonPTT(self, event):
|
||||
# pass
|
||||
#
|
||||
# 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):
|
||||
# pass
|
||||
#
|
||||
# def HeartBeat(self): # Called at about 10 Hz by the main
|
||||
# pass
|
||||
|
||||
def ImmediateChange(self, name, value):
|
||||
if DEBUG: print ("perseus hardware: ImmediateChange: perseus: name: %s value: %s" % (name, value))
|
||||
if name == 'perseus_setSampleRate_rx':
|
||||
value = int(value)
|
||||
self.application.OnBtnDecimation(rate=value)
|
||||
perseus.set_sampling_rate(value)
|
||||
self.curren_dec = value
|
||||
|
||||
|
||||
def VarDecimGetChoices(self): # Not used to set sample rate
|
||||
if DEBUG: print ("perseus hardware: VarDecimGetChoices")
|
||||
return list(map(str, self.rates)) # convert integer to string
|
||||
|
||||
def VarDecimGetLabel(self): # Return a text label for the decimation control.
|
||||
return 'Sample rates: '
|
||||
|
||||
def VarDecimGetIndex(self): # Return the index 0, 1, ... of the current decimation.
|
||||
for i in range(len(self.rates)):
|
||||
if self.rates[i] == self.current_rate:
|
||||
return i
|
||||
return 0
|
||||
|
||||
def VarDecimSet(self, index=None): # Called when the control is operated; if index==None, called on startup.
|
||||
print ("perseus hardware: VarDecimSet: index: %s" % (index))
|
||||
if index == None:
|
||||
if DEBUG: print ("perseus hardware: VarDecimSet: current sampling rate: %d" % self.current_rate)
|
||||
new_rate = self.current_rate = self.application.vardecim_set
|
||||
else:
|
||||
new_rate = self.rates[index]
|
||||
|
||||
if DEBUG: print ("perseus hardware: VarDecimSet: New sampling rate: %d" % new_rate)
|
||||
perseus.set_sampling_rate(int(new_rate))
|
||||
self.current_rate = int(new_rate)
|
||||
|
||||
return int(new_rate)
|
||||
|
||||
def VarDecimRange(self): # Return the lowest and highest sample rate.
|
||||
if DEBUG: print ("perseus hardware: VarDecimRange: %s" % self.rates)
|
||||
return (self.rates[0], self.rates[-1])
|
||||
|
||||
def OnButtonAntenna(self, event):
|
||||
btn = event.GetEventObject()
|
||||
n = btn.index
|
||||
if DEBUG: print ("OnButtonAntenna: %d status: %d" % (n, self.wb))
|
||||
self.wb = n
|
||||
perseus.set_input_filter (self.wb)
|
||||
|
||||
# def StartSamples(self): # called by the sound thread
|
||||
# print("perseus hardware: StartSamples")
|
||||
|
||||
# def StopSamples(self): # called by the sound thread
|
||||
# print("perseus hardware: StopSamples")
|
||||
@@ -0,0 +1,37 @@
|
||||
# Please do not change this widgets module for Quisk. Instead copy
|
||||
# it to your own quisk_widgets.py and make changes there.
|
||||
#
|
||||
# This module is used to add extra widgets to the QUISK screen.
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import math, wx
|
||||
|
||||
class BottomWidgets: # Add extra widgets to the bottom of the screen
|
||||
def __init__(self, app, hardware, conf, frame, gbs, vertBox):
|
||||
self.config = conf
|
||||
self.hardware = hardware
|
||||
self.application = app
|
||||
self.start_row = app.widget_row # The first available row
|
||||
self.start_col = app.button_start_col # The start of the button columns
|
||||
self.Widgets_0x06(app, hardware, conf, frame, gbs, vertBox)
|
||||
|
||||
def Widgets_0x06(self, app, hardware, conf, frame, gbs, vertBox):
|
||||
self.num_rows_added = 1
|
||||
start_row = self.start_row
|
||||
b1 = app.QuiskCheckbutton(frame, self.OnADC_dither, 'ADC Dither')
|
||||
gbs.Add(b1, (start_row, self.start_col), (1, 2), flag=wx.EXPAND)
|
||||
b2 = app.QuiskCheckbutton(frame, self.OnADC_preamp, 'ADC Preamp')
|
||||
gbs.Add(b2, (start_row, self.start_col + 2), (1, 2), flag=wx.EXPAND)
|
||||
|
||||
def OnADC_dither(self, event):
|
||||
btn = event.GetEventObject()
|
||||
value = btn.GetValue()
|
||||
self.hardware.get_hw().set_adc_dither (value)
|
||||
|
||||
def OnADC_preamp(self, event):
|
||||
btn = event.GetEventObject()
|
||||
value = btn.GetValue()
|
||||
self.hardware.get_hw().set_adc_preamp (value)
|
||||
@@ -0,0 +1,48 @@
|
||||
from distutils.core import setup, Extension
|
||||
import sys
|
||||
|
||||
module2 = Extension ('perseus',
|
||||
libraries = ['m', 'perseus-sdr'],
|
||||
sources = ['../import_quisk_api.c', 'perseus.c'],
|
||||
include_dirs = ['.', '..'],
|
||||
)
|
||||
|
||||
modulew2 = Extension ('perseus',
|
||||
sources = ['../import_quisk_api.c', 'perseus.c'],
|
||||
include_dirs = ['.', '..'],
|
||||
libraries = ['WS2_32', 'perseus-sdr'],
|
||||
)
|
||||
|
||||
if sys.platform == "win32":
|
||||
Modules = [modulew2]
|
||||
else:
|
||||
Modules = [module2]
|
||||
|
||||
setup (name = 'perseus',
|
||||
version = '0.1',
|
||||
description = 'perseus is an extension to Quisk to support Microtelecom Perseus SDR hardware',
|
||||
long_description = """Microtelecom Perseus SDR HF receiver.
|
||||
""",
|
||||
author = 'Andrea Montefusco IW0HDV',
|
||||
author_email = 'andrew@montefusco.com',
|
||||
url = 'http://www.montefusco.com',
|
||||
download_url = 'http://james.ahlstrom.name/quisk/',
|
||||
packages = ['quisk.perseuspkg'],
|
||||
package_dir = {'perseus' : '.'},
|
||||
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',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user