quisk-kc4upr/sdriqpkg/sdriq.c

917 lines
24 KiB
C
Executable File

#include <Python.h>
#ifdef MS_WINDOWS
#include <windows.h>
#include "ftd2xx.h"
#elif defined(__MACH__)
// Changes for MacOS support (__MACH__) thanks to Mario, DL3LSM.
#include "ftd2xx.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
#include <complex.h>
#define IMPORT_QUISK_API
#include "quisk.h"
#include "sdriq.h"
// 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
#define SDRIQ_BLOCK 8194
#define SDRIQ_BUF_SIZE 131072
#define INC_IREAD if (++iread >= SDRIQ_BUF_SIZE) iread = 0;
// Number of milliseconds to wait for SDR-IQ data on each read
#define SDRIQ_MSEC 4
// Timeout for SDR-IQ as a multiple of SDRIQ_MSEC
#define SDRIQ_TIMEOUT 50
// 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
static double sdriq_clock;
static int sdr_ack; // got ACK
static int sdr_nak; // got NAK
static char sdr_name[NAME_SIZE]; // control item 1
static char sdr_serial[NAME_SIZE]; // item 2
static int sdr_interface; // item 3
static int sdr_firmware; // item 4
static int sdr_bootcode; // item 4
static int sdr_status; // item 5
static int sdr_idle; // item 0x18, 1==idle, 2==run
static int sdriq_freq=7220000; // set SDR-IQ to this frequency
static int sdriq_gstate=2, sdriq_gain=127; // set SDR-IQ gain to this value
static int sdriq_decimation = 360; // set SDR-IQ decimation to this value
static int cur_freq, cur_gstate, cur_gain; // current value of frequency and gain
static int cur_decimation; // current value of decimation
// Changes for MacOS support (__MACH__) thanks to Mario, DL3LSM.
#if defined(MS_WINDOWS) || defined(__MACH__)
static FT_HANDLE quisk_sdriq_fd = INVALID_HANDLE_VALUE;
static int Read(void * buf, int bufsize)
{
DWORD bytes, rx_bytes;
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return 0;
if (FT_GetQueueStatus(quisk_sdriq_fd, &rx_bytes) != FT_OK) {
pt_quisk_sound_state->read_error++;
return 0;
}
if (rx_bytes > bufsize)
rx_bytes = bufsize;
if (rx_bytes == 0) {
return 0;
}
else if (FT_Read(quisk_sdriq_fd, buf, rx_bytes, &bytes) == FT_OK) {
return bytes;
}
else {
pt_quisk_sound_state->read_error++;
return 0;
}
}
static int Write(void * buf, int length)
{
DWORD bytes;
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return 0;
if (FT_Write(quisk_sdriq_fd, buf, length, &bytes) == FT_OK) {
return bytes;
}
else {
return 0;
}
}
#else
#define INVALID_HANDLE_VALUE -1
static int quisk_sdriq_fd = INVALID_HANDLE_VALUE;
static int Read(void * buf, int bufsize)
{
int res;
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return 0;
res = read(quisk_sdriq_fd, buf, bufsize);
if (res < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
pt_quisk_sound_state->read_error++;
}
return 0;
}
return res;
}
static int Write(void * buf, int length)
{
int res;
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return 0;
res = write(quisk_sdriq_fd, buf, length);
if (res <= 0)
return 0;
return res;
}
#endif
static void update_item(int item, const unsigned char * data)
{
switch(item) {
case 1:
strncpy(sdr_name, (char *)data, NAME_SIZE);
sdr_name[NAME_SIZE - 1] = 0;
break;
case 2:
strncpy(sdr_serial, (char *)data, NAME_SIZE);
sdr_serial[NAME_SIZE - 1] = 0;
break;
case 3:
sdr_interface = (data[1] << 8) | data[0];
break;
case 4:
if (data[0]) {
sdr_firmware = (data[2] << 8) | data[1];
#if DEBUG
printf ("Got firmware 0x%Xd\n", sdr_firmware);
#endif
}
else {
sdr_bootcode = (data[2] << 8) | data[1];
#if DEBUG
printf ("Got bootcode 0x%Xd\n", sdr_bootcode);
#endif
}
break;
case 5:
sdr_status = data[0];
if (data[0] == 0x20)
pt_quisk_sound_state->overrange++;
#if DEBUG
if (data[0] == 0x20)
printf ("Got overrange (clip)\n");
else
printf ("Got status 0x%X\n", data[0]);
#endif
break;
case 0x18:
sdr_idle = data[1];
#if DEBUG
if (sdr_idle == 1)
printf ("Got idle code IDLE\n");
else if (sdr_idle == 2)
printf ("Got idle code RUN\n");
else
printf ("Got idle code UNKNOWN\n");
#endif
break;
}
}
static void get_item( // Host sends a request for a control item
int item, // the item number
int nparams, // the length of params
char * params) // byte array of parameters, or NULL iff nparams==0
{
int length; // length of message block
char buf[64]; // message block header and control item and data
length = 4 + nparams;
if (length > 60)
return; // error
buf[0] = length & 0xFF; // length LSB
buf[1] = TYPE_HOST_GET | ((length >> 8) & 0x1F); // 3-bit type and 5-bit length MSB
buf[2] = item & 0xFF; // item LSB
buf[3] = (item >> 8) & 0xFF; // item MSB
if (nparams)
memcpy(buf + 4, params, nparams);
if (Write(buf, length) != length) {
pt_quisk_sound_state->read_error++;
#if DEBUG
printf("get_item write error\n");
#endif
}
#if DEBUG > 1
printf ("get_item 0x%X\n", item);
#endif
return;
}
static void set_item( // host command to set a control item
int item, // the item number
int nparams, // the length of params
char * params) // byte array of parameters, or NULL iff nparams==0
{
int length;
char buf[64]; // message block header and control item and data
length = 4 + nparams; // total length
if (length > 60)
return; // error
buf[0] = length & 0xFF; // length LSB
buf[1] = TYPE_HOST_SET | ((length >> 8) & 0x1F); // 3-bit type and 5-bit length MSB
buf[2] = item & 0xFF; // item LSB
buf[3] = (item >> 8) & 0xFF; // item MSB
if (nparams)
memcpy(buf + 4, params, nparams);
if (Write(buf, length) != length) {
pt_quisk_sound_state->read_error++;
#if DEBUG
printf("set_item write error\n");
#endif
}
#if DEBUG > 1
printf ("set_item 0x%X\n", item);
#endif
}
// The ft245 driver does not have a circular buffer for input; bytes are just appended
// to the buffer. When all bytes are read and the buffer goes empty, the pointers are reset to zero.
// Be sure to empty out the ft245 frequently so its buffer does not overflow.
static int sdr_recv(complex double * samp, int sampsize)
{ // Read all data from the SDR-IQ and process it.
// Return the number >= 0 of I/Q data samples that are available in samp.
int k, res, item, navail, nSamples;
short ii, qq;
unsigned char buf128[128];
static unsigned char buf[SDRIQ_BUF_SIZE];
static int iread=0;
static int iwrite=0;
static int state=0;
static int length;
static int type;
static int sample_count;
nSamples = 0; // number of samples added to samp
// first read all characters from the ft245 driver into our large buffer
if (iread == 0) {
k = SDRIQ_BUF_SIZE - iwrite - 1;
if (k > 65536) // maximum read for ft245
k = 65536;
if (k > 0) {
res = Read(buf + iwrite, k);
iwrite += res;
}
}
else if (iread <= iwrite) {
k = SDRIQ_BUF_SIZE - iwrite;
if (k > 65536) // maximum read for ft245
k = 65536;
res = Read(buf + iwrite, k);
if (res == k)
iwrite = 0;
else if (res > 0)
iwrite += res;
}
if (iread > iwrite) {
k = iread - iwrite - 1;
if (k > 65536) // maximum read for ft245
k = 65536;
if (k > 0) {
res = Read(buf + iwrite, k);
iwrite += res;
}
}
// Now process the data we have in buf
start_here:
if (iread > iwrite) // calculate number of available bytes: navail
navail = SDRIQ_BUF_SIZE - iread + iwrite;
else
navail = iwrite - iread;
if (state == 0) { // starting state; we need to read the first two bytes for length and type
if (navail < 2)
return nSamples; // no more data available
// we have the first two bytes
length = buf[iread];
INC_IREAD
type = (buf[iread] >> 5) & 0x7; // 3-bit type
length |= (buf[iread] & 0x1F) << 8; // length including header
INC_IREAD
#if DEBUG > 1
if (length != 0 && !(type == 3 && length == 3))
printf("Got message type %d length %d\n", type, length);
#endif
if (type > 3 && length == 0) // data block with zero length
length = 8194; // special data length
length -= 2; // we read two bytes; length is the remaining bytes
if (length < 0) {
state = 9; // bad length; attempt resync
}
else if (length == 0) { // NAK
sdr_nak = 1;
#if DEBUG
printf("Got NAK\n");
#endif
// state remains at zero
}
else if (samp && length > 50 && length < 8192) { // No such message; we are out of sync
state = 9;
}
else if (samp && type == 4 && length == 8192) { // ADC samples data block
state = 5;
sample_count = 2048;
}
else if (navail >= length) {
state = 3;
}
else {
state = 2;
}
goto start_here; // process the next state
}
else if (state == 2) { // waiting for all "length" bytes to be read
if (navail < length)
return nSamples; // partially read block
state = 3;
goto start_here; // process the next state
}
else if (state == 3) { // we have all the bytes of the record available
if (length == 1 && type == 3) { // ACK
sdr_ack = buf[iread];
INC_IREAD
#if DEBUG > 1
printf("Got ACK for 0x%X\n", sdr_ack);
#endif
}
else if ((type == 0 || type == 1) && length >= 2) { // control item
item = buf[iread];
INC_IREAD
item |= buf[iread] << 8; // control item number
INC_IREAD
length -= 2;
for (k = 0; k < length; k++) {
if (k < 128)
buf128[k] = buf[iread];
INC_IREAD
}
update_item(item, buf128);
}
else {
iread += length; // discard block
if (iread >= SDRIQ_BUF_SIZE)
iread -= SDRIQ_BUF_SIZE;
}
state = 0;
goto start_here; // we read a whole block
}
else if (state == 5) { // read available samples into samp
//ptimer(4096);
while (navail >= 4 && sample_count && nSamples < sampsize) { // samples are 16-bit little-endian
ii = buf[iread]; // assumes a short is two bytes
INC_IREAD
ii |= buf[iread] << 8;
INC_IREAD
qq = buf[iread];
INC_IREAD
qq |= buf[iread] << 8;
INC_IREAD
navail -= 4; // we read four bytes
// convert 16-bit samples to 32-bit samples
samp[nSamples++] = 65536.0 * ii + 65536.0 * qq * I; // return sample as complex number
sample_count--; // we added one sample
}
//printf("State %d navail %d sample_count %d nSamples %d\n", state, navail, sample_count, nSamples);
if (sample_count > 0) // no more samples available
return nSamples; // return the available samples
state = 0; // this block was completely read
goto start_here; // process the next state
}
else if (state == 9) { // try to re-synchronize
pt_quisk_sound_state->read_error++;
#if DEBUG
printf ("Lost sync: type %d length %d\n", type, length);
#endif
while (1) { // empty the buffer
if (Read(buf, 1024) == 0)
break;
}
#if DEBUG > 2
printf("Buffer is empty\n");
#endif
while (1) { // look for the start of data blocks "\x00\x80"
res = Read(buf, 1);
if (res != 1) {
QuiskSleepMicrosec(SDRIQ_MSEC * 1000);
}
else if (state == 9) { // look for 0x00
if (buf[0] == 0x00)
state = 10;
}
else { // state 10: look for 0x80
if (buf[0] == 0x80) {
state = 5;
iread = iwrite = 0;
sample_count = 2048;
#if DEBUG
printf("Regained sync\n");
#endif
break; // we probably have a data block start
}
else if (buf[0] != 0x00) {
state = 9;
}
}
}
goto start_here; // process the next state
}
return nSamples; // should not happen
}
static void set_ad6620( // host command to set an AD6620 register
int address, // the register address
int value) // the value; up to 4 bytes
{
char buf[12];
buf[0] = '\x09';
buf[1] = '\xA0';
buf[2] = address & 0xFF; // low byte
buf[3] = (address >> 8) & 0xFF; // high byte
buf[4] = value & 0xFF; // low byte
value = value >> 8;
buf[5] = value & 0xFF;
value = value >> 8;
buf[6] = value & 0xFF;
value = value >> 8;
buf[7] = value & 0xFF;
buf[8] = 0;
if (Write(buf, 9) != 9) {
pt_quisk_sound_state->read_error++;
#if DEBUG
printf ("set_ad6620 write error\n");
#endif
}
#if DEBUG > 1
printf ("set_ad6620 address 0x%X\n", address);
#endif
}
static void wset_ad6620(int address, int value)
{ // Set AD6620 register and wait for ACK
int i;
sdr_ack = -1;
set_ad6620(address, value);
for (i = 0; i < SDRIQ_TIMEOUT; i++) {
sdr_recv(NULL, 0);
if (sdr_ack != -1)
break;
QuiskSleepMicrosec(SDRIQ_MSEC * 1000);
}
#if DEBUG
if (sdr_ack != 1)
printf ("Failed to get ACK for AD6620 address 0x%X\n", address);
#endif
}
static void set_freq_sdriq(void) // Set SDR-IQ frequency
{
char buf[8];
int freq;
freq = sdriq_freq;
buf[0] = 0;
buf[1] = freq & 0xFF; // low byte
freq = freq >> 8;
buf[2] = freq & 0xFF;
freq = freq >> 8;
buf[3] = freq & 0xFF;
freq = freq >> 8;
buf[4] = freq & 0xFF;
buf[5] = 1;
set_item(0x0020, 6, buf);
cur_freq = sdriq_freq;
}
static void set_gain_sdriq(void)
{
char buf[2];
switch (sdriq_gstate) {
case 0:
buf[0] = 0;
buf[1] = sdriq_gain & 0xFF;
break;
case 1:
buf[0] = 1;
buf[1] = sdriq_gain & 0x7F;
buf[1] |= 0x80;
break;
case 2:
buf[0] = 1;
buf[1] = sdriq_gain & 0x7F;
break;
}
set_item(0x0038, 2, buf);
cur_gstate = sdriq_gstate;
cur_gain = sdriq_gain;
}
static void program_ad6620(void) // Set registers
{
int i;
struct ad6620 *pt;
switch (sdriq_decimation) {
case 360:
pt = &dec360;
break;
case 500:
pt = &dec500;
break;
case 600:
pt = &dec600;
break;
case 1250:
pt = &dec1250;
break;
default:
pt = &dec1250;
break;
}
wset_ad6620(0x300, 1); // soft reset
for (i = 0; i < 256; i++)
wset_ad6620(i, pt->coef[i]);
wset_ad6620(0x301, 0);
wset_ad6620(0x302, -1);
wset_ad6620(0x303, 0);
wset_ad6620(0x304, 0);
wset_ad6620(0x305, pt->Scic2);
wset_ad6620(0x306, pt->Mcic2 - 1);
wset_ad6620(0x307, pt->Scic5);
wset_ad6620(0x308, pt->Mcic5 - 1);
wset_ad6620(0x309, pt->Sout);
wset_ad6620(0x30A, pt->Mrcf - 1);
wset_ad6620(0x30B, 0);
wset_ad6620(0x30C, 255);
wset_ad6620(0x30D, 0);
set_freq_sdriq();
set_gain_sdriq();
wset_ad6620(0x300, 0);
cur_decimation = sdriq_decimation;
}
#if defined(MS_WINDOWS) || defined(__MACH__)
static void quisk_open_sdriq_dev(const char * name, char * buf, int bufsize)
{
#if DEBUG
FT_STATUS ftStatus;
FT_DEVICE_LIST_INFO_NODE *devInfo;
DWORD numDevs;
int i;
// create the device information list
ftStatus = FT_CreateDeviceInfoList(&numDevs);
if (ftStatus == FT_OK) {
printf("Number of devices is %d\n", (int)numDevs);
}
else {
printf("Number of devices failed\n");
numDevs = 0;
}
if (numDevs > 0) {
// allocate storage for list based on numDevs
devInfo = (FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
// get the device information list
ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs);
if (ftStatus == FT_OK) {
for (i = 0; i < numDevs; i++) {
printf("Dev %d:\n",i);
printf(" Flags=0x%x\n", (unsigned int)devInfo[i].Flags);
printf(" Type=0x%x\n", (unsigned int)devInfo[i].Type);
printf(" ID=0x%x\n", (unsigned int)devInfo[i].ID);
printf(" LocId=0x%x\n", (unsigned int)devInfo[i].LocId);
printf(" SerialNumber=%s\n", devInfo[i].SerialNumber);
printf(" Description=%s\n", devInfo[i].Description);
printf(" ftHandle=0x%x\n", (unsigned int)devInfo[i].ftHandle);
}
}
free(devInfo);
}
#endif // DEBUG
if (FT_OpenEx ("SDR-IQ", FT_OPEN_BY_DESCRIPTION, &quisk_sdriq_fd) != FT_OK) {
strncpy(buf, "Open SDR-IQ failed", bufsize);
quisk_sdriq_fd = INVALID_HANDLE_VALUE;
return;
}
if (FT_SetTimeouts(quisk_sdriq_fd, 2, 100) != FT_OK) {
strncpy(buf, "Set Timeouts failed", bufsize);
return;
}
}
#else
static void quisk_open_sdriq_dev(const char * name, char * buf, int bufsize)
{
struct termios newtio;
quisk_sdriq_fd = open(name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (quisk_sdriq_fd < 0) {
strncpy(buf, "Open SDR-IQ : ", bufsize);
strncat(buf, strerror(errno), bufsize - strlen(buf) - 1);
quisk_sdriq_fd = INVALID_HANDLE_VALUE;
return;
}
if (isatty(quisk_sdriq_fd)) { // Thanks to Stephen Hurd for improvements
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
cfsetispeed(&newtio, B230400);
cfsetospeed(&newtio, B230400);
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; // specify non-blocking read
newtio.c_cc[VMIN] = 0;
tcflush(quisk_sdriq_fd, TCIFLUSH);
tcsetattr(quisk_sdriq_fd, TCSANOW, &newtio);
}
else { // use ft245 or similar driver
}
return;
}
#endif
static void quisk_open_sdriq(const char * name, char * buf, int bufsize)
{
char buf1024[1024];
int i, freq;
quisk_open_sdriq_dev(name, buf, bufsize);
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return; // error
sdr_name[0] = 0;
sdr_serial[0] = 0;
sdr_idle = -1; // unknown state
set_item(0x0018, 4, "\x81\x01\x00\x00");
QuiskSleepMicrosec(1000000);
while (1) { // read and discard any available output
if (Read(buf1024, 1024) == 0)
break;
}
set_item(0x0018, 4, "\x81\x01\x00\x00");
get_item(0x0002, 0, NULL); // request serial number
get_item(0x0005, 0, NULL); // request status
// set sample rate
freq = sdriq_clock;
buf1024[0] = 0;
buf1024[1] = freq & 0xFF; // low byte
freq = freq >> 8;
buf1024[2] = freq & 0xFF;
freq = freq >> 8;
buf1024[3] = freq & 0xFF;
freq = freq >> 8;
buf1024[4] = freq & 0xFF;
set_item(0x00B0, 5, buf1024); // set actual clock speed
get_item(0x0001, 0, NULL); // request name
// loop for input
for (i = 0; i < SDRIQ_TIMEOUT; i++) {
sdr_recv(NULL, 0);
if (sdr_name[0] != 0)
break;
QuiskSleepMicrosec(SDRIQ_MSEC * 1000);
}
if (sdr_name[0]) { // we got a response
snprintf(buf, bufsize, "Capture from %s serial %s.",
sdr_name, sdr_serial);
program_ad6620();
}
else {
snprintf(buf, bufsize, "No response from SDR-IQ");
}
#if DEBUG
printf ("%s\n", buf);
#endif
}
static void WaitForPoll(void)
{
static double time0 = 0; // time in seconds
double timer; // time remaining from last poll usec
timer = pt_quisk_sound_state->data_poll_usec - (QuiskTimeSec() - time0) * 1e6;
if (timer > 1000.0) // see if enough time has elapsed
QuiskSleepMicrosec((int)timer); // wait for the remainder of the poll interval
time0 = QuiskTimeSec(); // reset starting time value
}
// End of most SDR-IQ 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:
// Start sample capture; called from the sound thread.
static void quisk_start_sdriq(void)
{
if (sdr_idle != 2)
set_item(0x0018, 4, "\x81\x02\x00\x01");
}
// Stop sample capture; called from the sound thread.
static void quisk_stop_sdriq(void)
{
int msec;
complex double samples[2048];
for (msec = 0; msec < 1001; msec++) {
if (msec % 100 == 0)
set_item(0x0018, 4, "\x81\x01\x00\x00");
sdr_recv(samples, 2048);
if (sdr_idle == 1)
break;
QuiskSleepMicrosec(1000);
}
#if DEBUG
if (msec < 1001)
printf("quisk_stop_sdriq succeeded\n");
else
printf("quisk_stop_sdriq timed out\n");
#endif
}
// Called in a loop to read samples; called from the sound thread.
static int quisk_read_sdriq(complex double * cSamples)
{
int length;
WaitForPoll();
if (quisk_sdriq_fd == INVALID_HANDLE_VALUE)
return -1; // sdriq is closed
length = sdr_recv(cSamples, SAMP_BUFFER_SIZE); // get all available samples
if (cur_freq != sdriq_freq) // check frequency
set_freq_sdriq();
if (cur_gstate != sdriq_gstate || cur_gain != sdriq_gain) // check gain
set_gain_sdriq();
if (cur_decimation != sdriq_decimation) { // check decimation
quisk_stop_sdriq();
program_ad6620();
quisk_start_sdriq();
}
return length; // return number of samples
}
// 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;
if (quisk_sdriq_fd != INVALID_HANDLE_VALUE) {
sdr_idle = -1; // unknown state
#if defined(MS_WINDOWS) || defined(__MACH__)
FT_Close(quisk_sdriq_fd);
#else
close(quisk_sdriq_fd);
#endif
quisk_sdriq_fd = INVALID_HANDLE_VALUE;
}
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 * name;
char buf[128];
if (!PyArg_ParseTuple (args, ""))
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(&quisk_start_sdriq, &quisk_stop_sdriq, &quisk_read_sdriq);
//////////////
quisk_open_sdriq(name, buf, 128); // SDR-IQ 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.
// Set the receive frequency; called from the GUI thread.
static PyObject * freq_sdriq(PyObject * self, PyObject * args)
{
if (!PyArg_ParseTuple (args, "i", &sdriq_freq))
return NULL;
Py_INCREF (Py_None);
return Py_None;
}
// Set the preamp gain; called from the GUI thread.
static PyObject * gain_sdriq(PyObject * self, PyObject * args) // Called from GUI thread
{ // gstate == 0: Gain must be 0, -10, -20, or -30
// gstate == 1: Attenuator is on and gain is 0 to 127 (7 bits)
// gstate == 2: Attenuator is off and gain is 0 to 127 (7 bits)
if (!PyArg_ParseTuple (args, "ii", &sdriq_gstate, &sdriq_gain))
return NULL;
Py_INCREF (Py_None);
return Py_None;
}
// Set the decimation; called from the GUI thread.
static PyObject * set_decimation(PyObject * self, PyObject * args)
{
if (!PyArg_ParseTuple (args, "i", &sdriq_decimation))
return NULL;
Py_INCREF (Py_None);
return Py_None;
}
// Functions callable from Python are listed here:
static PyMethodDef QuiskMethods[] = {
{"open_samples", open_samples, METH_VARARGS, "Open the RfSpace SDR-IQ."},
{"close_samples", close_samples, METH_VARARGS, "Close the RfSpace SDR-IQ."},
{"freq_sdriq", freq_sdriq, METH_VARARGS, "Set the frequency of the SDR-IQ"},
{"gain_sdriq", gain_sdriq, METH_VARARGS, "Set the gain of the SDR-IQ"},
{"set_decimation", set_decimation, METH_VARARGS, "Set the decimation of the SDR-IQ"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION < 3
// Python 2.7:
// Initialization, and registration of public symbol "initsdriq":
PyMODINIT_FUNC initsdriq (void)
{
if (Py_InitModule ("sdriq", 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 sdriqmodule = {
PyModuleDef_HEAD_INIT,
"sdriq",
NULL,
-1,
QuiskMethods
} ;
PyMODINIT_FUNC PyInit_sdriq(void)
{
PyObject * m;
m = PyModule_Create(&sdriqmodule);
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