Quisk version 4.2.28

This commit is contained in:
James C. Ahlstrom
2023-12-26 15:39:37 -05:00
commit ffa047c2ef
143 changed files with 52434 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
The files in this afedrinet directory came from http://www.afedri-sdr.com. Only slight
modifications were made by N2ADR. Thanks Alex!!!
N2ADR: Changes made 26 January 2019.
+1
View File
@@ -0,0 +1 @@
#
+1
View File
@@ -0,0 +1 @@
gcc -o afedrinet_io.pyd --shared afedrinet_io.c ../is_key_down.c ../import_quisk_api.c -O3 -I"../" -I"C:\Programs\Python27\include" -L"C:\Programs\Python27\libs" -lws2_32 -lpython27
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
#replace include path and library name to right one for your system
# for example for Python 2.7 it will look like -I"/usr/include/python2.7/" -lpython2.7
gcc -o afedrinet_io.so --shared afedrinet_io.c ../is_key_down.c ../import_quisk_api.c -fPIC -O3 -I"../" -I"/usr/include/python2.7/" -lpython2.7
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
#replace include path and library name to right one for your system
# for example for Python 2.7 it will look like -I"/usr/include/python2.7/" -lpython2.7
#/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7
gcc -o afedrinet_io.so --shared afedrinet_io.c ../is_key_down.c ../import_quisk_api.c -I"../" -I"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7/" -L"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/" -lpython2.7
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/python
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
##################################################
# AFEDRI Class module
# Title: afedri.py
# Author: k3it
# Adopted to work with Quisk
# by 4Z5LV
# Last Changes: Sat Feb 02 2013
# Version: 2.2
# Adapted to work with Python3
# by N2ADR
# Last Changes: January 2020
##################################################
from socket import *
import wave
import sys
import struct
import time
import datetime
import string
import math
class afedri(object):
"""
class definition for the Afedri SDR-NET
"""
def __init__(self,sdr_address="0.0.0.0", sdr_port=50000):
if sdr_address == "0.0.0.0":
__sdr_address,self.sdr_port = self.__discover_afedri()
if __sdr_address is None:
self.s = None
return
else:
__sdr_address = sdr_address
self.sdr_port = sdr_port
self.s = socket(AF_INET, SOCK_STREAM)
self.s.settimeout(2)
try:
self.s.connect((__sdr_address,self.sdr_port))
#print ("Established control connection with AFEDRI")
except:
print ("Error connecting to SDR")
##sys.exit()
self.s.close()
self.s = None
def close(self):
if self.s:
self.s.close()
self.s = None
def set_center_freq(self,target_freq):
if not self.s: return 1
__next_freq = target_freq
__next_freq = struct.pack("<q",__next_freq)
__set_freq_cmd = b"\x0a\x00\x20\x00\x00" + __next_freq[:5]
self.s.send(__set_freq_cmd)
__data = self.s.recv(10)
__freq = __data[5:] + b"\x00\x00\x00"
__freq = struct.unpack("<q",__freq)[0]
return __freq
def set_samp_rate(self,target_samprate):
if not self.s: return 1
#__samp_rate = target_samprate
__samp_rate = struct.pack("<L",target_samprate)
__set_rate_cmd = b"\x09\x00\xB8\x00\x00" + __samp_rate[:4]
self.s.send(__set_rate_cmd)
__data = self.s.recv(9)
__samp = __data[5:] + b"\x00\x00\x00\x00"
__samp = struct.unpack("<q",__samp)[0]
return __samp
def set_gain(self,target_gain):
if not self.s: return 1
__gain = target_gain
# special afedri calculation for the gain byte
__gain = ((__gain+10)/3 << 3) + 1
__set_gain_cmd = b"\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
self.s.send(__set_gain_cmd)
__data = self.s.recv(6)
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
return __rf_gain
def set_gain_indx(self,indx):
if not self.s: return 1
__gain = (indx << 3) + 1
# special afedri calculation for the gain byte
#__gain = ((__gain+10)/3 << 3) + 1
__set_gain_cmd = b"\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
self.s.send(__set_gain_cmd)
__data = self.s.recv(6)
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
return __rf_gain
def get_gain(self):
"""
NOT IMPLEMENTED IN AFEDRI?. DON'T USE
"""
if not self.s: return 1
__get_gain_cmd = b"\x05\x20\x38\x00\x00"
self.s.send(__get_gain_cmd)
__data = self.s.recv(6)
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:])[0]>>3)
return __rf_gain
def get_fe_clock(self):
if not self.s: return 1
__get_lword_cmd = b"\x09\xE0\x02\x55\x00\x00\x00\x00\x00"
__get_hword_cmd = b"\x09\xE0\x02\x55\x01\x00\x00\x00\x00"
self.s.send(__get_lword_cmd)
__data_l = self.s.recv(9)
self.s.send(__get_hword_cmd)
__data_h = self.s.recv(9)
__fe_clock = struct.unpack("<H",__data_l[4:6])[0] + (struct.unpack("<H",__data_h[4:6])[0]<<16)
return __fe_clock
def start_capture(self):
#start 16-bit contiguous capture, complex numbers
if not self.s: return 1
__start_cmd=b"\x08\x00\x18\x00\x80\x02\x00\x00"
self.s.send(__start_cmd)
__data = self.s.recv(8)
return __data
def get_sdr_name(self):
#Request SDR's Name string command = array.array('B',[0x4, 0x20,1,0])
if not self.s: return 1
__start_cmd=b"\x04\x20\x01\x00"
self.s.send(__start_cmd)
__data = self.s.recv(16)
__data = __data.decode('utf-8')
return __data
def stop_capture(self):
if not self.s: return 1
__stop_cmd=b"\x08\x00\x18\x00\x00\x01\x00\x00"
self.s.send(__stop_cmd)
__data = self.s.recv(8)
return __data
def __discover_afedri(self):
# attempt to find AFEDRI SDR on the network
# using AE4JY Simple Network Discovery Protocol
__DISCOVER_SERVER_PORT=48321 # PC client Tx port, SDR Server Rx Port
__DISCOVER_CLIENT_PORT=48322 # PC client Rx port, SDR Server Tx Port
__data=b"\x38\x00\x5a\xa5" # magic discovery packet
__data=__data.ljust(56,b"\x00") # pad with zeroes
self.s = socket(AF_INET, SOCK_DGRAM)
self.s.bind(('', 0))
self.s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
self.sin = socket(AF_INET, SOCK_DGRAM)
self.sin.bind(('', __DISCOVER_CLIENT_PORT))
#exception if no response to broadcast
self.sin.settimeout(1)
self.s.sendto(__data, ('<broadcast>',__DISCOVER_SERVER_PORT))
try:
__msg=self.sin.recv(256,0)
__devname=__msg[5:20]
__devname=__devname.decode('utf-8')
__sn=__msg[21:36]
__sn=__sn.decode('utf-8')
__ip=inet_ntoa(__msg[40:36:-1])
__port=struct.unpack("<H",__msg[53:55])[0]
self.s.close()
self.sin.close()
print ("found ", __devname, __sn, __ip, __port)
return (__ip,__port)
except timeout:
print ("No response from AFEDRI on the LAN")
##sys.exit()
return None, None
def __del__(self):
self.stop_capture()
if self.s: self.s.close()
"""
# verify and correct sampling rate according to the main clock speed
# Alex Trushkin code 4z5lv:
fe_main_clock_freq = a.get_fe_clock()
tmp_div = fe_main_clock_freq / (4 * samp_rate)
floor_div = math.floor(tmp_div)
if (tmp_div - floor_div >= 0.5):
floor_div += 1
if floor_div < 15:
floor_div = 15
#print ("Warning: Max supported sampling rate is", math.floor(fe_main_clock_freq / (4 * floor_div)))
elif floor_div > 625:
floor_div = 625
#print ("Warning: Min supported sampling rate is", math.floor(fe_main_clock_freq / (4 * floor_div)))
dSR = fe_main_clock_freq / (4 * floor_div)
floor_SR = math.floor(dSR)
if (dSR - floor_SR >= 0.5):
floor_SR += 1
if floor_SR != samp_rate:
print ("Warning: invalid sample rate selected for the AFEDRI main clock (", fe_main_clock_freq, "Hz )")
print (" setting to the next valid value", samp_rate, " => ", floor_SR)
samp_rate = floor_SR
"""
+399
View File
@@ -0,0 +1,399 @@
#include <Python.h>
#ifdef MS_WINDOWS
#include <Winsock2.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#endif
#ifdef MS_WINDOWS
#define QUISK_SHUT_RD SD_RECEIVE
#define QUISK_SHUT_BOTH SD_BOTH
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#define SOCKET int
#define INVALID_SOCKET -1
#define QUISK_SHUT_RD SHUT_RD
#define QUISK_SHUT_BOTH SHUT_RDWR
#endif
#include <complex.h>
#define IMPORT_QUISK_API
#include "quisk.h"
//#include "sdriq.h"
static SOCKET rx_udp_socket = INVALID_SOCKET; // Socket for receiving ADC samples from UDP
static int rx_udp_started = 0; // Have we received any data yet?
static int rx_udp_read_blocks = 0; // Number of blocks to read for each read call
static double rx_udp_gain_correct = 1; // For decimation by 5, correct by 4096 / 5**5
static int use_remove_dc=0; // Remove DC from samples
//static int quisk_using_udp = 0;
// This module provides access to the SDR-IQ by RfSpace. It is the source
// for the Python extension module sdriq. It can be used as a model for an
// extension module for other hardware. Read the end of this file for more
// information. 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.
// Start of SDR-IQ specific code:
//
#define DEBUG 0
// Type field for the message block header; upper 3 bits of byte
#define TYPE_HOST_SET 0
#define TYPE_HOST_GET (1 << 5)
#define NAME_SIZE 16
//#define UDP_BROADCAST
#ifdef UDP_BROADCAST
#define FIRST_IQ_DATA_IDX 20
#define RX_UDP_SIZE 1044 // Expected size of UDP samples packet
#else
#define RX_UDP_SIZE 1028 // Expected size of UDP samples packet
#define FIRST_IQ_DATA_IDX 4
#endif
#define BROADCAST_HEADER_SIZE 16
#define UDP_PROTCOL_ID1 0x04
#define UDP_PROTCOL_ID2 0x18
#ifdef DEBUG_IO
#undef DEBUG_IO
#define DEBUG_IO 1
#endif
static PyObject * open_rx_udp(const char * ip, int port)
{
// const char * ip;
// int port;
char buf[128];
struct sockaddr_in Addr;
int recvsize;
char optval;
#if DEBUG_IO
int intbuf;
#ifdef MS_WINDOWS
int bufsize = sizeof(int);
#else
socklen_t bufsize = sizeof(int);
#endif
#endif
#ifdef MS_WINDOWS
WORD wVersionRequested;
WSADATA wsaData;
#endif
// if (!PyArg_ParseTuple (args, "si", &ip, &port))
// return NULL;
// port = 50000;
#ifdef MS_WINDOWS
wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0) {
sprintf(buf, "Failed to initialize Winsock (WSAStartup)");
return PyString_FromString(buf);
}
#endif
// quisk_using_udp = 1;
rx_udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (rx_udp_socket != INVALID_SOCKET)
{
optval=1;
setsockopt( rx_udp_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
recvsize = 256000;
setsockopt(rx_udp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, sizeof(recvsize));
memset(&Addr, 0, sizeof(Addr));
Addr.sin_family = AF_INET;
Addr.sin_port = htons(port);
Addr.sin_addr.s_addr = htonl(INADDR_ANY);//inet_addr("192.168.0.8");
// Addr.sin_addr.S_un.S_addr = inet_addr(ip);
// if (connect(rx_udp_socket, (const struct sockaddr *)&Addr, sizeof(Addr)) != 0)
if (bind(rx_udp_socket, (const struct sockaddr *)&Addr, sizeof(Addr)) != 0)
{
shutdown(rx_udp_socket, QUISK_SHUT_BOTH);
close(rx_udp_socket);
rx_udp_socket = INVALID_SOCKET;
sprintf(buf, "Failed to connect to UDP %s port %u", ip, port);
}
else {
sprintf(buf, "Capture from UDP %s port %u", ip, port);
#if DEBUG_IO
if (getsockopt(rx_udp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&intbuf, &bufsize) == 0)
{
printf("UDP socket receive buffer size %d\n", intbuf);
printf("address %s port %u\n", ip, port);
}
else
printf ("Failure SO_RCVBUF\n");
#endif
}
}
else {
sprintf(buf, "Failed to open socket");
}
return PyString_FromString(buf);
}
static PyObject * close_rx_udp(PyObject * self, PyObject * args)
{
short msg = 0x7373; // shutdown
if (!PyArg_ParseTuple (args, ""))
return NULL;
if (rx_udp_socket != INVALID_SOCKET) {
shutdown(rx_udp_socket, QUISK_SHUT_RD);
send(rx_udp_socket, (char *)&msg, 2, 0);
send(rx_udp_socket, (char *)&msg, 2, 0);
QuiskSleepMicrosec(3000000);
close(rx_udp_socket);
rx_udp_socket = INVALID_SOCKET;
}
rx_udp_started = 0;
// if (quisk_using_udp) {
// quisk_using_udp = 0;
#ifdef MS_WINDOWS
WSACleanup();
#endif
// }
Py_INCREF (Py_None);
return Py_None;
}
int afedri_read_rx_udp(complex * samp) // Read samples from UDP
{ // Size of complex sample array is SAMP_BUFFER_SIZE
ssize_t bytes;
//int SR = 0;
static int sample_rate = 0; // Sample rate such as 48000, 96000, 192000
unsigned char buf[1500]; // Maximum Ethernet is 1500 bytes.
static unsigned short seq0; // must be 8 bits
unsigned short seq_curr = 0;
#ifdef MS_WINDOWS
__int32 i, count, nSamples, xr, xi, index;
#else
int32_t i, count, nSamples, xr, xi, index;
#endif
unsigned char * ptxr, * ptxi;
static complex dc_average = 0; // Average DC component in samples
static complex dc_sum = 0;
static int dc_count = 0;
static int dc_key_delay = 0;
// Data from the receiver is little-endian
// if ( !rx_udp_read_blocks)
if(sample_rate != pt_quisk_sound_state->sample_rate)
{
sample_rate = pt_quisk_sound_state->sample_rate;
// "rx_udp_read_blocks" is the number of UDP blocks to read at once
rx_udp_read_blocks = (int)(pt_quisk_sound_state->data_poll_usec * 1e-6 * sample_rate + 0.5);
rx_udp_read_blocks = (rx_udp_read_blocks + (RX_UDP_SIZE / 12)) / (RX_UDP_SIZE / 6); // 6 bytes per sample
if (rx_udp_read_blocks < 1)
rx_udp_read_blocks = 1;
#if DEBUG_IO
printf("read_rx_udp: rx_udp_read_blocks %d\n", rx_udp_read_blocks);
#endif
}
/* if ( ! rx_udp_gain_correct) {
int dec;
dec = (int)(rx_udp_clock / sample_rate + 0.5);
if ((dec / 5) * 5 == dec) // Decimation by a factor of 5
rx_udp_gain_correct = 1.31072;
else // Decimation by factors of two
rx_udp_gain_correct = 1.0;
}
*/
nSamples = 0;
for (count = 0; count < rx_udp_read_blocks; count++)
{ // read several UDP blocks
#if DEBUG_IO
// printf("Data RX Process Begin %u\n",count);
#endif
bytes = recv(rx_udp_socket, (char *)buf, RX_UDP_SIZE, 0); // blocking read
if (bytes != RX_UDP_SIZE) { // Known size of sample block
pt_quisk_sound_state->read_error++;
#if DEBUG_IO
printf("read_rx_udp: Bad block size %i\n", (int)bytes);
#endif
continue;
}
// buf[0] is the sequence number
// buf[1] is the status:
// bit 0: key up/down state
// bit 1: set for ADC overrange (clip)
seq_curr = buf[2] | (buf[3] << 8);
if (seq_curr != seq0) {
#if DEBUG_IO
printf("read_rx_udp: Bad sequence want %3d got %3d at block %d of %d\n",
(unsigned int)seq0, (unsigned int)buf[0], count, rx_udp_read_blocks);
#endif
pt_quisk_sound_state->read_error++;
}
seq0 = seq_curr + 1; // Next expected sequence number
// quisk_set_key_down(buf[1] & 0x01); // bit zero is key state
// if (buf[1] & 0x02) // bit one is ADC overrange
// quisk_sound_state.overrange++;
index = FIRST_IQ_DATA_IDX;
ptxr = (unsigned char *)&xr;
ptxi = (unsigned char *)&xi;
// convert 24-bit samples to 32-bit samples; int must be 32 bits.
while (index < bytes)
{
xr = xi = 0;
memcpy (ptxr + 2, buf + index, 2);
index += 2;
memcpy (ptxi + 2, buf + index, 2);
index += 2;
samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct;
xr = xi = 0;
memcpy (ptxr + 2, buf + index, 2);
index += 2;
memcpy (ptxi + 2, buf + index, 2);
index += 2;
samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct;;
//if (nSamples == 2) printf("%12d %12d\n", xr, xi);
}
}
if (quisk_is_key_down()) {
dc_key_delay = 0;
dc_sum = 0;
dc_count = 0;
}
else if (dc_key_delay < pt_quisk_sound_state->sample_rate) {
dc_key_delay += nSamples;
}
else {
dc_count += nSamples;
for (i = 0; i < nSamples; i++) // Correction for DC offset in samples
dc_sum += samp[i];
if (dc_count > pt_quisk_sound_state->sample_rate * 2) {
dc_average = dc_sum / dc_count;
dc_sum = 0;
dc_count = 0;
//printf("dc average %lf %lf %d\n", creal(dc_average), cimag(dc_average), dc_count);
//printf("dc polar %.0lf %d\n", cabs(dc_average),
// (int)(360.0 / 2 / M_PI * atan2(cimag(dc_average), creal(dc_average))));
}
}
if (use_remove_dc)
for (i = 0; i < nSamples; i++) // Correction for DC offset in samples
samp[i] -= dc_average;
// printf("%u\n", pt_quisk_sound_state->sample_rate);
return nSamples;
}
// End of most AFEDRI specific code.
///////////////////////////////////////////////////////////////////////////
// The API requires at least two Python functions for Open and Close, plus
// additional Python functions as needed. And it requires exactly three
// C funcions for Start, Stop and Read samples. Quisk runs in two threads,
// a GUI thread and a sound thread. You must not call the GUI or any Python
// code from the sound thread. You must return promptly from functions called
// by the sound thread.
//
// The calling sequence is Open, Start, then repeated calls to Read, then
// Stop, then Close.
// Start of Application Programming Interface (API) code:
// Called to close the sample source; called from the GUI thread.
static PyObject * close_samples(PyObject * self, PyObject * args)
{
if (!PyArg_ParseTuple (args, ""))
return NULL;
close_rx_udp(self, args);
Py_INCREF (Py_None);
return Py_None;
}
// Called to open the sample source; called from the GUI thread.
static PyObject * open_samples(PyObject * self, PyObject * args)
{
const char * ip;
int port;
// const char * name;
// char buf[128];
if (!PyArg_ParseTuple (args, "si", &ip, &port))
return NULL;
// name = QuiskGetConfigString("sdriq_name", "NoName");
// sdriq_clock = QuiskGetConfigDouble("sdriq_clock", 66666667.0);
// Record our C-language Start/Stop/Read functions for use by sound.c.
quisk_sample_source(NULL, NULL, &afedri_read_rx_udp);
//////////////
return open_rx_udp(ip, port); // AFEDRI specific
// return PyString_FromString(buf); // return a string message
}
// Miscellaneous functions needed by the SDR-IQ; called from the GUI thread as
// a result of button presses.
// Functions callable from Python are listed here:
static PyMethodDef QuiskMethods[] = {
{"open_samples", open_samples, METH_VARARGS, "Open the AFEDRI SDR-Net."},
{"close_samples", close_samples, METH_VARARGS, "Close the AFEDRI SDR-Net."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION < 3
// Python 2.7:
PyMODINIT_FUNC initafedrinet_io (void)
{
if (Py_InitModule ("afedrinet_io", 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 afedrinet_iomodule = {
PyModuleDef_HEAD_INIT,
"afedrinet_io",
NULL,
-1,
QuiskMethods
} ;
PyMODINIT_FUNC PyInit_afedrinet_io(void)
{
PyObject * m;
m = PyModule_Create(&afedrinet_iomodule);
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
+7
View File
@@ -0,0 +1,7 @@
afedrinet2:
python2 setup.py build_ext --force --inplace
afedrinet3:
python3 setup.py build_ext --force --inplace
+61
View File
@@ -0,0 +1,61 @@
# This is a sample quisk_conf.py configuration file for Microsoft Windows.
# For Windows, your default config file name is "My Documents/quisk_conf.py",
# but you can use a different config file by using -c or --config. Quisk creates
# an initial default config file if there is none. To control Quisk, edit
# "My Documents/quisk_conf.py" using any text editor; for example WordPad (not Notepad).
# In Windows you can see what sound devices you have, and you can set the Primary
# Device for capture and playback by using Control Panel/Sounds and Audio Devices.
# If you have only one sound device, it should be set as "Primary". If you have
# several, find the names by using Control Panel/Sounds and Audio Devices; for
# example, you may have "SoundMAX HD Audio" in the list for "Sound playback" and
# "Sound recording". To specify this device for capture (recording) or playback,
# enter a unique part of its name using exact upper/lower case. For example:
# name_of_sound_capture = "SoundMAX"
# name_of_sound_play = "SoundMAX"
# There are many possible options for your config file. Copy the ones you want
# from the master file quisk_conf_defaults.py (but don't change the master file).
# The master config file is located in the site-packages/quisk folder for Python 2.7.
# This file is Python code and the comment character is "#". To ignore a line,
# start it with "#". To un-ignore a line, remove the "#". Generally you must start
# lines in column one (the left edge) except for logic blocks.
from afedrinet import quisk_hardware # Use different hardware file
use_rx_udp = 1 # Get ADC samples from UDP
rx_udp_ip = "192.168.0.8" # Sample source IP address
rx_udp_port = 50000 # Sample source UDP port
rx_udp_clock = 79998382 # ADC sample rate in Hertz
#rx_udp_decimation = 8 * 8 * 8 # Decimation from clock to UDP sample rate
#sample_rate = int(float(rx_udp_clock) / rx_udp_decimation + 0.5) # Don't change this
data_poll_usec = 10000
#sample_rate = 192000 # ADC hardware sample rate in Hertz
sample_rate = 740740 # ADC hardware sample rate in Hertz
playback_rate = 48000 # Radio sound play rate
name_of_sound_capt = ""#AFEDRI-SDR-Net Audio" # Name of soundcard capture hardware device.
name_of_sound_play = "Buil-in Output" # Use the same device for play back.
#name_of_sound_play = "Line 1"#Virtual Audio Cable" # Use the same device for play back.
latency_millisecs = 50 # latency time in milliseconds
display_fraction = 0.92 # The edges of the full bandwidth are not valid
default_rf_gain = 11
# Select the default screen when Quisk starts:
#default_screen = 'Graph'
default_screen = 'WFall'
# If you use hardware with a fixed VFO (crystal controlled SoftRock) un-comment the following:
# import quisk_hardware_fixed as quisk_hardware
# fixed_vfo_freq = 7056000
# If you use an SDR-IQ for capture, first install the SpectraView software
# that came with the SDR-IQ. This will install the USB driver. Then set these parameters:
# import quisk_hardware_sdriq as quisk_hardware # Use different hardware file
# use_sdriq = 1 # Capture device is the SDR-IQ
# sdriq_name = "SDR-IQ" # Name of the SDR-IQ device to open
# sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal)
# sdriq_decimation = 500 # Must be 360, 500, 600, or 1250
# sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this
# name_of_sound_capt = "" # We do not capture from the soundcard
# playback_rate = 48000 # Radio sound play rate, default 48000
# display_fraction = 0.85 # The edges of the full bandwidth are not valid
+54
View File
@@ -0,0 +1,54 @@
# This is a sample quisk_conf.py configuration file for Linux
# For Windows, your default config file name is "/home/user/quisk_conf.py"
# but you can use a different config file by using -c or --config. Quisk creates
# an initial default config file if there is none. To control Quisk, edit
# "/home/user/quisk_conf.py" using any text editor; for example WordPad (not Notepad).
# In Windows you can see what sound devices you have, and you can set the Primary
# Device for capture and playback by using Control Panel/Sounds and Audio Devices.
# If you have only one sound device, it should be set as "Primary". If you have
# several, find the names by using Control Panel/Sounds and Audio Devices; for
# example, you may have "SoundMAX HD Audio" in the list for "Sound playback" and
# "Sound recording". To specify this device for capture (recording) or playback,
# enter a unique part of its name using exact upper/lower case. For example:
# name_of_sound_capture = "SoundMAX"
# name_of_sound_play = "SoundMAX"
# There are many possible options for your config file. Copy the ones you want
# from the master file quisk_conf_defaults.py (but don't change the master file).
# The master config file is located in the site-packages/quisk folder for Python 2.7.
# This file is Python code and the comment character is "#". To ignore a line,
# start it with "#". To un-ignore a line, remove the "#". Generally you must start
# lines in column one (the left edge) except for logic blocks.
from afedrinet import quisk_hardware # Use different hardware file
use_rx_udp = 1 # Get ADC samples from UDP
rx_udp_ip = "192.168.0.8" # Sample source IP address
rx_udp_port = 50000 # Sample source UDP port
rx_udp_clock = 80000000 # ADC sample rate in Hertz
#rx_udp_decimation = 8 * 8 * 8 # Decimation from clock to UDP sample rate
#sample_rate = int(float(rx_udp_clock) / rx_udp_decimation + 0.5) # Don't change this
data_poll_usec = 10000
#sample_rate = 192000 # ADC hardware sample rate in Hertz
sample_rate = 740740 # ADC hardware sample rate in Hertz
playback_rate = 48000 # Radio sound play rate
name_of_sound_capt = ""#AFEDRI-SDR-Net Audio" # Name of soundcard capture hardware device.
name_of_sound_play = "portaudiodefault"#hw:0,0" # Use the same device for play back.
#name_of_sound_play = "Line 1"#Virtual Audio Cable" # Use the same device for play back.
latency_millisecs = 50 # latency time in milliseconds
display_fraction = 0.92 # The edges of the full bandwidth are not valid
default_rf_gain = 14
# Select the default screen when Quisk starts:
#default_screen = 'Graph'
default_screen = 'WFall'
# If you use hardware with a fixed VFO (crystal controlled SoftRock) un-comment the following:
# import quisk_hardware_fixed as quisk_hardware
# fixed_vfo_freq = 7056000
# If you use an SDR-IQ for capture, first install the SpectraView software
# that came with the SDR-IQ. This will install the USB driver. Then set these parameters:
# import quisk_hardware_sdriq as quisk_hardware # Use different hardware file
# use_sdriq = 1 # Capture device is the SDR-IQ
# sdriq_name = "SDR-IQ" # Name of the SDR-IQ device to open
# sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal)
# sdriq_decimation = 500 # Must be 360, 500, 600, or 1250
# sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this
# name_of_sound_capt = "" # We do not capture from the soundcard
# playback_rate = 48000 # Radio sound play rate, default 48000
# display_fraction = 0.85 # The edges of the full bandwidth are not valid
+54
View File
@@ -0,0 +1,54 @@
# This is a sample quisk_conf.py configuration file for Linux
# For Windows, your default config file name is "/home/user/quisk_conf.py"
# but you can use a different config file by using -c or --config. Quisk creates
# an initial default config file if there is none. To control Quisk, edit
# "/home/user/quisk_conf.py" using any text editor; for example WordPad (not Notepad).
# In Windows you can see what sound devices you have, and you can set the Primary
# Device for capture and playback by using Control Panel/Sounds and Audio Devices.
# If you have only one sound device, it should be set as "Primary". If you have
# several, find the names by using Control Panel/Sounds and Audio Devices; for
# example, you may have "SoundMAX HD Audio" in the list for "Sound playback" and
# "Sound recording". To specify this device for capture (recording) or playback,
# enter a unique part of its name using exact upper/lower case. For example:
# name_of_sound_capture = "SoundMAX"
# name_of_sound_play = "SoundMAX"
# There are many possible options for your config file. Copy the ones you want
# from the master file quisk_conf_defaults.py (but don't change the master file).
# The master config file is located in the site-packages/quisk folder for Python 2.7.
# This file is Python code and the comment character is "#". To ignore a line,
# start it with "#". To un-ignore a line, remove the "#". Generally you must start
# lines in column one (the left edge) except for logic blocks.
from afedrinet import quisk_hardware # Use different hardware file
use_rx_udp = 1 # Get ADC samples from UDP
rx_udp_ip = "192.168.0.8" # Sample source IP address
rx_udp_port = 50000 # Sample source UDP port
rx_udp_clock = 80000000 # ADC sample rate in Hertz
#rx_udp_decimation = 8 * 8 * 8 # Decimation from clock to UDP sample rate
#sample_rate = int(float(rx_udp_clock) / rx_udp_decimation + 0.5) # Don't change this
data_poll_usec = 10000
#sample_rate = 192000 # ADC hardware sample rate in Hertz
sample_rate = 740740 # ADC hardware sample rate in Hertz
playback_rate = 48000 # Radio sound play rate
name_of_sound_capt = ""#AFEDRI-SDR-Net Audio" # Name of soundcard capture hardware device.
name_of_sound_play = "portaudiodefault"#hw:0,0" # Use the same device for play back.
#name_of_sound_play = "Line 1"#Virtual Audio Cable" # Use the same device for play back.
latency_millisecs = 50 # latency time in milliseconds
display_fraction = 0.92 # The edges of the full bandwidth are not valid
default_rf_gain = 14
# Select the default screen when Quisk starts:
#default_screen = 'Graph'
default_screen = 'WFall'
# If you use hardware with a fixed VFO (crystal controlled SoftRock) un-comment the following:
# import quisk_hardware_fixed as quisk_hardware
# fixed_vfo_freq = 7056000
# If you use an SDR-IQ for capture, first install the SpectraView software
# that came with the SDR-IQ. This will install the USB driver. Then set these parameters:
# import quisk_hardware_sdriq as quisk_hardware # Use different hardware file
# use_sdriq = 1 # Capture device is the SDR-IQ
# sdriq_name = "SDR-IQ" # Name of the SDR-IQ device to open
# sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal)
# sdriq_decimation = 500 # Must be 360, 500, 600, or 1250
# sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this
# name_of_sound_capt = "" # We do not capture from the soundcard
# playback_rate = 48000 # Radio sound play rate, default 48000
# display_fraction = 0.85 # The edges of the full bandwidth are not valid
+94
View File
@@ -0,0 +1,94 @@
# Please do not change this hardware control module.
# It provides support for the SDR-IQ by RfSpace.
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
#import _quisk as QS
import os,sys
#sys.path.append('./afedri')
try:
import afedrinet_io as AF
from sdr_control import *
except:
from afedrinet import afedrinet_io as AF
from afedrinet.sdr_control import *
from ctypes import *
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
#from quisk import App as parent
from quisk_hardware_model import Hardware as BaseHardware
#from quisk import *
class Hardware(BaseHardware):
def __init__(self, app, conf):
BaseHardware.__init__(self, app, conf)
self.local_tune = 2
self.index = 0
self.clock = 80000000
self.old_LO_freq = 0
self.rf_gain_labels = ('RF -10','RF -7','RF -4','RF -1','+2','+5','+8','+11','+14','+17','+20','+23','+26','+29','+32','+35')
self.conf = conf
self.plugin = Control(self.conf.rx_udp_ip, self.conf.rx_udp_port)
self.app = app
self.decimations = [] # supported decimation rates
for dec in (53333, 96000, 133333, 185185, 192000, 370370, 740740, 1333333):
self.decimations.append(dec)
def open(self):
self.plugin.OpenHW() # Return a config message
RF_Gain_idx = int((10 + self.conf.default_rf_gain) / 3)
if not 0 <= RF_Gain_idx < len(self.rf_gain_labels):
RF_Gain_idx = 0
self.plugin.SetAttenuator(RF_Gain_idx)
self.app.BtnRfGain.SetIndex(RF_Gain_idx)
#print ("RF Gain %i" % self.conf.default_rf_gain)
return AF.open_samples(self.conf.rx_udp_ip, self.conf.rx_udp_port)
def close(self):
self.plugin.CloseHW()
def OnButtonRfGain(self, event):
btn = event.GetEventObject()
n = btn.index
if n > -1 or n < 16 :
self.plugin.SetAttenuator(n)
else:
print ('Unknown RfGain')
def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
self.local_tune = tune
if vfo:
self.plugin.SetHWLO(vfo)
return tune, vfo
def ReturnFrequency(self): # Return the current tuning and VFO frequency
return (None, None) # Return LO frequency
def GetFirmwareVersion(self):
return 226
def HeartBeat(self):
# self.PrintStatus('Start', 'AFEDRI')
return
def VarDecimGetChoices(self): # Return a list/tuple of strings for the decimation control.
l = [] # a list of sample rates
for dec in self.decimations:
l.append(str( dec ))
return l
def VarDecimGetLabel(self): # return a text label for the control
return "Sample rate sps"
def VarDecimGetIndex(self): # return the current index
return self.index
def VarDecimSet(self, index=None): # set decimation, return sample rate
if index is None: # initial call to set decimation before the call to open()
rate = self.application.vardecim_set # May be None or from different hardware
try:
dec = rate #int(float(self.conf.rx_udp_clock / rate + 0.5))
self.index = self.decimations.index(dec)
except:
try:
self.index = self.decimations.index(self.conf.sample_rate)
except:
self.index = 0
else:
self.index = index
dec = self.decimations[self.index]
self.plugin.SetHWSR(dec) # Return a config message
return dec
+38
View File
@@ -0,0 +1,38 @@
Hello All!
I want to publish here some information about possibility to use Quisk application on MAC computers running MAC OSX.
It is for experienced MAC OS users that know what is Terminal and command shell tools and how to compile executable from source code:
1. You should download Quisk package from author's web page
2. Xcode SDK and command tools
3. Install macports to manage ports that required to be used with Quisk
4. You should install the next packages:
python27, py27-wxpython-2.8, fftw-3.0 , portaudio, pulseaudio and probably some additional
5. Be ready that packages installation will take long time. Select macports python as default python executable:
>> sudo port select --set python python27
6. After you will extract Quisk files from archive to separate directory you must enter Quisk directory and compile Quisk for your system running next command:
>> make macports
7. After installation to use Quisk with AFEDRi SDR, you have to download additional packages: afedriusb , afedrinet extract contains of archive to separated folders afedriusb and afedrinet in main Quisk directory.
8. For network connected AFEDRI you must enter afedrinet folder and compile SDR support library running afe_library script, before you can run this script you must modify path to python library and include folders in this script, for example on my MAC it looks like:
###############################################################
gcc -o afedrinet_io.so --shared afedrinet_io.c ../is_key_down.c ../import_quisk_api.c -I"../" -I"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7/" -L"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/" -lpython2.7
###################################################################
9. For USB connection you must download the sdr_commander v1.22
Extract archive to separate folder and compile source code.
After successful compilation you will get executable sdr_commander, you must
copy it to quick/afedriusb folder
10.
10. Edit qusik_conf.py file to define correct sound device (card) name, copy this file as .quisk_conf.py to user's home directory.
For example for portaudio devices it will look like this one:
#################################################################
from afedriusb import quisk_hardware
sample_rate = 185185
name_of_sound_capt = "portaudio#2"
name_of_sound_play = "portaudiodefault"
latency_millisecs = 150
default_rf_gain = 14
default_screen = 'WFall'
playback_rate = 48000
default 48000
##########################################################
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/python # This is client.py file
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import os,sys
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
import afedrinet
import afedrinet.afedri
class Control:
def __init__(self, sdr_address="192.168.0.8", sdr_port=50000):
self.hw = afedrinet.afedri.afedri(sdr_address, sdr_port)
if self.hw.s is None: # Failure to find the hardware
self.hw = None
def OpenHW(self):
if not self.hw: return
data = self.hw.get_sdr_name()
print (data[4:])
self.hw.start_capture()
def CloseHW(self):
if not self.hw: return
self.hw.stop_capture()
self.hw.close # Close the socket when done
def SetHWLO(self, vfo):
if not self.hw: return
self.hw.set_center_freq(vfo)
def SetHWSR(self, sample_rate):
if not self.hw: return
self.hw.set_samp_rate(sample_rate)
print ("Sample Rate %i" % sample_rate)
def SetAttenuator(self, indx):
if not self.hw: return
self.hw.set_gain_indx(indx)
+49
View File
@@ -0,0 +1,49 @@
from distutils.core import setup, Extension
import sys
# Afedri hardware support added by Alex, Alex@gmail.com
if sys.platform == "win32":
Modules = [
Extension ('afedrinet.afedrinet_io',
libraries = ['WS2_32'],
sources = ['../import_quisk_api.c', '../is_key_down.c', 'afedrinet_io.c'],
include_dirs = ['.', '..'],
)
]
else:
Modules = [
Extension ('afedrinet.afedrinet_io',
libraries = ['m'],
sources = ['../import_quisk_api.c', '../is_key_down.c', 'afedrinet_io.c'],
include_dirs = ['.', '..'],
)
]
setup (name = 'afedrinet_io',
version = '0.1',
description = 'Afedri',
long_description = "Afedri.",
author = 'Alex',
author_email = 'Alex@gmail.com',
#url = 'http://',
download_url = 'http://james.ahlstrom.name/quisk/',
packages = ['afedrinet.afedrinet_io'],
package_dir = {'afedrinet' : '.'},
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',
],
)
+16
View File
@@ -0,0 +1,16 @@
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import os,sys
from ctypes import *
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
from sdr_control import *
#import sdr_control
#class self(control)
cnt = Control()
cnt.OpenHW()
cnt.SetHWLO(28050000)
cnt.SetHWSR(740740)
cnt.CloseHW()