first commit

This commit is contained in:
2025-10-20 20:11:21 +02:00
commit cbf3c258e0
318 changed files with 41712 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
#define SAMPRATE 560000 // 1.12MS/s
#define LNB_REF 24000UL // kHz
#define BASEQRG 10489470UL // kHz, spectrum range ist 10489.470 - 10490.03
#define RXBASEQRG ((BASEQRG - 390UL*LNB_REF)*1000UL)
#define TXBASEQRG ((2400000UL - 30UL)*1000UL)
#define PLUTOBUFSIZE (SAMPRATE/10)
#define MHZ(x) ((long long)(x*1000000.0 + .5))
#define GHZ(x) ((long long)(x*1000000000.0 + .5))
enum iodev {
RX = 0,
TX
};
typedef struct _stream_cfg_ {
long long bw_hz; // Analog bandwidth in Hz
long long fs_hz; // Baseband sample rate in Hz
long long lo_hz; // Local oscillator frequency in Hz
const char* rfport; // Port name
} stream_cfg;
bool get_ad9361_stream_ch(__notused struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn);
bool cfg_ad9361_streaming_ch(struct iio_context *ctx, stream_cfg *cfg, enum iodev type, int chid);
bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev);
int pluto_get_USB(char *sn);
void pluto_setup();
void init_runloop();
void setTXfrequency(long long freq);
void setRXfrequency(long long freq);
void setTXpower();
void release_ptt();
void set_ptt();
extern stream_cfg rxcfg;
extern stream_cfg txcfg;
extern struct iio_context *ctx;
extern struct iio_buffer *rxbuf;
extern struct iio_buffer *txbuf;
extern struct iio_channel *rx0_i;
extern struct iio_channel *tx0_i;
extern float RX_BW;
extern float TX_BW;
extern double RX_FREQ;
extern double TX_FREQ;
extern float TX_GAIN;
extern char pluto_context_name[50];
+221
View File
@@ -0,0 +1,221 @@
/*
* Adalm Pluto Driver
* ==================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* =======================================
* various subroutines to access the pluto
* =======================================
*
* most subroutines from here:
* https://raw.githubusercontent.com/analogdevicesinc/libiio/master/examples/ad9361-iiostream.c
*
*/
#include "../qo100trx.h"
void setTXfrequency(long long freq);
// static scratch mem for strings
static char tmpstr[64];
// check return value of attr_write function
static void errchk(int v, const char* what)
{
if (v < 0)
{
printf("Error %d writing to channel \"%s\"\nvalue may not be supported.\n", v, what);
}
}
// write attribute: double
static void wr_ch_double(struct iio_channel *chn, const char* what, double val)
{
errchk(iio_channel_attr_write_double(chn, what, val), what);
}
// write attribute: long long int
static void wr_ch_lli(struct iio_channel *chn, const char* what, long long val)
{
errchk(iio_channel_attr_write_longlong(chn, what, val), what);
}
// write attribute: string
static void wr_ch_str(struct iio_channel *chn, const char* what, const char* str)
{
errchk(iio_channel_attr_write(chn, what, str), what);
}
// helper function generating channel names
static char* get_ch_name(const char* type, int id)
{
snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id);
return tmpstr;
}
// returns ad9361 phy device
static struct iio_device* get_ad9361_phy(struct iio_context *ctx)
{
struct iio_device *dev = iio_context_find_device(ctx, "ad9361-phy");
return dev;
}
// finds AD9361 streaming IIO devices
bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev)
{
switch (d) {
case TX: *dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); return *dev != NULL;
case RX: *dev = iio_context_find_device(ctx, "cf-ad9361-lpc"); return *dev != NULL;
}
return 0;
}
// finds AD9361 streaming IIO channels
bool get_ad9361_stream_ch(__notused struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn)
{
*chn = iio_device_find_channel(dev, get_ch_name("voltage", chid), d == TX);
if (!*chn)
*chn = iio_device_find_channel(dev, get_ch_name("altvoltage", chid), d == TX);
return *chn != NULL;
}
// finds AD9361 phy IIO configuration channel with id chid
static bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn)
{
switch (d) {
case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), false); return *chn != NULL;
case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), true); return *chn != NULL;
}
return 0;
}
// finds AD9361 local oscillator IIO configuration channels
static bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn)
{
switch (d) {
// LO chan is always output, i.e. true
case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 0), true); return *chn != NULL;
case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 1), true); return *chn != NULL;
}
return 0;
}
// applies streaming configuration through IIO
bool cfg_ad9361_streaming_ch(struct iio_context *ctx, stream_cfg *cfg, enum iodev type, int chid)
{
struct iio_channel *chn = NULL;
// Configure phy and lo channels
if (!get_phy_chan(ctx, type, chid, &chn)) { return false; }
wr_ch_str(chn, "rf_port_select", cfg->rfport);
wr_ch_lli(chn, "rf_bandwidth", cfg->bw_hz);
//printf("write sampling_frequency: %lld\n",cfg->fs_hz);
wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz);
if(type == TX)
{
//wr_ch_double(chn, "hardwaregain", txcfg.hwgain);
setTXpower();
setTXfrequency(cfg->lo_hz);
}
else
{
// show possible values: iio_attr -n 192.168.20.25 -c ad9361-phy voltage0
wr_ch_str(chn, "gain_control_mode","slow_attack");
//wr_ch_str(chn, "gain_control_mode","manual");
//wr_ch_lli(chn, "hardwaregain", 66);
// Configure LO channel
setRXfrequency(cfg->lo_hz);
}
return true;
}
int lasttxpower = -1;
void setTXpower()
{
if(txpower != lasttxpower)
{
if(txpower > 0) txpower = 0; // 0 is pluto's max value
lasttxpower = txpower;
printf("set TX power to %d dBm\n",txpower);
struct iio_channel *chn = NULL;
if (!get_phy_chan(ctx, TX, 0, &chn)) { return; }
// txpower=-40: switches OFF the PTT in the F5OEO firmware
wr_ch_double(chn, "hardwaregain", (double)txpower);
}
}
void set_ptt()
{
lasttxpower = -1;
setPort("p", 1);
}
void release_ptt()
{
printf("release PTT by setting -40dBm\n");
// set the power to -40, this releases the GPO0,1 PTT in the F5OEO firmware (>V.2021)
struct iio_channel *chn = NULL;
if (!get_phy_chan(ctx, TX, 0, &chn)) { return; }
wr_ch_double(chn, "hardwaregain", (double)-40);
setPort("p", 0);
}
long long lastfreq = 0;
void setTXfrequency(long long freq)
{
freq += refoffset;
if(freq != lastfreq)
{
lastfreq = freq;
//printf("************* TX-QRG *************** %lld, offset:%d\n",freq,refoffset);
struct iio_channel *chn = NULL;
if (!get_lo_chan(ctx, TX, &chn)) { return; }
wr_ch_lli(chn, "frequency", freq);
}
}
long long lastrxfreq = 0;
void setRXfrequency(long long freq)
{
freq += refoffset;
if(freq != lastrxfreq)
{
lastrxfreq = freq;
//printf("************* RX-QRG *************** %lld, offset:%d\n",freq,refoffset);
struct iio_channel *chn = NULL;
if (!get_lo_chan(ctx, RX, &chn)) { return; }
wr_ch_lli(chn, "frequency", freq);
}
}
Binary file not shown.
+116
View File
@@ -0,0 +1,116 @@
/*
* Adalm Pluto Driver
* ==================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* ==========================================
* find a pluto connected via USB or Ethernet
* ==========================================
*
*/
#include "../qo100trx.h"
char pluto_context_name[50];
int pluto_get_IP(char *url_IP)
{
// === connect Pluto at a given IP address ===
struct sockaddr_in sa;
int res = inet_pton(AF_INET,url_IP+3,&(sa.sin_addr));
if(res == 1)
{
// we have a valid pluto IP continue using this IP
sprintf(pluto_context_name,"%s",url_IP);
//printf("searching Pluto on %s\n",pluto_context_name);
return 1;
}
//printf("cannot evaluate %s\n",url_IP);
return 0;
}
int pluto_get_USB(char *sn)
{
char s[500];
snprintf(s,499,"iio_info -s 2>/dev/null");
s[499] = 0;
pluto_context_name[0] = 0;
FILE *fp = popen(s,"r");
if(fp)
{
while (fgets(s, sizeof(s)-1, fp) != NULL)
{
// get the USB id
char usbid[50];
char usbsn[100];
char *hp = strstr(s,"[usb:");
if(hp)
{
hp += 1;
char *he = strchr(hp,']');
if(he)
{
*he = 0;
strncpy(usbid,hp,49);
usbid[sizeof(usbid)-1] = 0;
// read serial number
char *psn = strstr(s,"serial=");
if(psn)
{
psn+=7;
char *spn = strchr(psn,' ');
if(spn)
{
*spn = 0;
strncpy(usbsn,psn,99);
usbsn[sizeof(usbsn)-1] = 0;
printf("PLUTO found, SN:%s ID:%s\n",usbsn,usbid);
// if no special pluto requested, then use the first found pluto
if(*sn == 0)
{
strcpy(pluto_context_name, usbid);
return 1;
}
// search for a specific SN
if(!strcmp(sn, usbsn))
{
strcpy(pluto_context_name, usbid);
return 1;
}
}
}
}
}
}
pclose(fp);
}
else
printf("cannot execute iio_info command\n");
printf("no PLUTO found\n");
return 0;
}
Binary file not shown.
+83
View File
@@ -0,0 +1,83 @@
/*
* Adalm Pluto Driver
* ==================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* =========================
* runloop for RX and TX
* =========================
*
*/
#include "../qo100trx.h"
void* plutorun_threadfunction(void* param);
void init_runloop()
{
pthread_t plutorunthread;
pthread_create(&plutorunthread, NULL, plutorun_threadfunction, NULL);
}
void* plutorun_threadfunction(void* param)
{
ssize_t nbytes_rx, nbytes_tx;
uint8_t *p_dat, *p_start;
pthread_detach(pthread_self());
printf("entering pluto loop, *** PID:%ld ***\n",syscall(SYS_gettid));
while(keeprunning)
{
// ====== receive samples from pluto ======
// Refill RX buffer
nbytes_rx = iio_buffer_refill(rxbuf);
if (nbytes_rx < 0) { printf("Error refilling buf %d\n",(int) nbytes_rx); }
//measure_samplerate(0,nbytes_rx/4,10);
p_start = (uint8_t *)iio_buffer_first(rxbuf, rx0_i);
//for(int ix=0; ix<nbytes_rx; ix++)
// measure_maxval(p_start[ix]);
// sample buffer begins at p_start with length (PLUTOBUFSIZE * p_inc) bytes
write_fifo(RXfifo,p_start,nbytes_rx);
write_fifo(FFTfifo,p_start,nbytes_rx);
// ====== send samples to pluto ======
// get samples received via UDP
static uint8_t pidata[PLUTOBUFSIZE*4];
int lenfifo = read_fifo(TXfifo, pidata, PLUTOBUFSIZE*4);
if(lenfifo)
{
p_dat = (uint8_t *)iio_buffer_first(txbuf, tx0_i);
memcpy(p_dat,pidata,PLUTOBUFSIZE*4);
nbytes_tx = iio_buffer_push(txbuf);
if (nbytes_tx < 0) { printf("Error pushing buf %d\n", (int) nbytes_tx); }
}
usleep(1000);
}
printf("exit pluto loop\n");
pthread_exit(NULL); // self terminate this thread
return NULL;
}
BIN
View File
Binary file not shown.
+139
View File
@@ -0,0 +1,139 @@
/*
* Adalm Pluto Driver
* ==================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* =========================
* setup pluto for RX and TX
* =========================
*
*/
#include "../qo100trx.h"
// ============= Configuration =============
float RX_BW = 1; // MHz
float TX_BW = 0.1; // MHz
double RX_FREQ = (double)RXBASEQRG; // Hz
double TX_FREQ = (double)TXBASEQRG; // Hz
// =========================================
// device context
struct iio_context *ctx = NULL;
// Streaming devices
struct iio_device *tx;
struct iio_device *rx;
// channels
struct iio_channel *rx0_i = NULL;
struct iio_channel *rx0_q = NULL;
struct iio_channel *tx0_i = NULL;
struct iio_channel *tx0_q = NULL;
// buffers
struct iio_buffer *rxbuf = NULL;
struct iio_buffer *txbuf = NULL;
// Stream configurations
stream_cfg rxcfg;
stream_cfg txcfg;
void pluto_setup()
{
int ret;
// set default configuration from pluto.h
uint32_t srate = (uint32_t)SAMPRATE;
if(srate < 2100000) srate = 3000000;
// RX stream config
rxcfg.bw_hz = MHZ(RX_BW); // rx rf bandwidth
rxcfg.fs_hz = srate; // rx sample rate
rxcfg.lo_hz = RX_FREQ; // rx rf frequency
rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)
// TX stream config
txcfg.bw_hz = MHZ(TX_BW); // tx rf bandwidth
txcfg.fs_hz = srate; // tx sample rate (must be same as RX samp rate)
txcfg.lo_hz = TX_FREQ; // tx rf frequency
txcfg.rfport = "A"; // port A (select for rf freq.)
printf("RX frequency : %f MHz\n", (double)rxcfg.lo_hz / 1e6);
printf("TX frequency : %f MHz\n", (double)txcfg.lo_hz / 1e6);
printf("Samplerate : %f MHz\n", (double)SAMPRATE / 1e6);
printf("RX Bandwidth : %f MHz\n", (double)rxcfg.bw_hz / 1e6);
printf("TX Bandwidth : %f MHz\n", (double)txcfg.bw_hz / 1e6);
printf("TX Gain : %d dBm\n",txpower);
// Initialize Pluto
ctx = iio_create_context_from_uri(pluto_context_name);
if(!ctx) {printf("Cannot find a pluto at: %s\n", pluto_context_name); exit(0);}
int devanz = iio_context_get_devices_count(ctx);
if(devanz <= 0)
{
printf("NO Pluto devices found\n");
exit(0);
}
// noch keine PTT
ret = get_ad9361_stream_dev(ctx, TX, &tx);
if(!ret) {printf("TX streaming device not found. Pluto error %d\n",errno); exit(0);}
ret = get_ad9361_stream_dev(ctx, RX, &rx);
if(!ret) {printf("RX streaming device not found. Pluto error %d\n",errno); exit(0);}
cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0);
// with the following command the F5OEO Firmware activates the PTT on GPIO
cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0);
get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i);
get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q);
get_ad9361_stream_ch(ctx, TX, tx, 0, &tx0_i);
get_ad9361_stream_ch(ctx, TX, tx, 1, &tx0_q);
if(SAMPRATE < 2100000)
{
iio_device *dev9 = iio_context_find_device(ctx, "ad9361-phy");
ad9361_set_bb_rate(dev9,(unsigned long)SAMPRATE);
}
iio_channel_enable(rx0_i);
iio_channel_enable(rx0_q);
iio_channel_enable(tx0_i);
iio_channel_enable(tx0_q);
rxbuf = iio_device_create_buffer(rx, PLUTOBUFSIZE, false);
if (!rxbuf) {
perror("Could not create RX buffer");
}
txbuf = iio_device_create_buffer(tx, PLUTOBUFSIZE, false);
if (!txbuf) {
perror("Could not create TX buffer");
}
// Pluto init finished
// create capture/playback thread
init_runloop();
}
Binary file not shown.