From d08a904ee3382569a3d1ab3f21c6827453de0d3d Mon Sep 17 00:00:00 2001 From: Doolan_R Date: Fri, 25 Nov 2022 08:39:32 +0000 Subject: [PATCH 1/2] add hackrf --- Makefile | 19 +- dump1090.c | 635 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 613 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index f9637b7eb..b5b9ceeea 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,22 @@ -CFLAGS?=-O2 -g -Wall -W $(shell pkg-config --cflags librtlsdr) -LDLIBS+=$(shell pkg-config --libs librtlsdr) -lpthread -lm +CFLAGS?=-O2 -g -Wall -W $(shell pkg-config --cflags librtlsdr libhackrf libairspy soxr) +LDLIBS+=$(shell pkg-config --libs librtlsdr libhackrf libairspy soxr) -lpthread -lm + +ifeq ($(NoSDRplay),1) +CFLAGS+= -DNoSDRplay +else +LDLIBS+= -lmirsdrapi-rsp +endif + CC?=gcc PROGNAME=dump1090 -all: dump1090 +all: $(PROGNAME) %.o: %.c $(CC) $(CFLAGS) -c $< -dump1090: dump1090.o anet.o - $(CC) -g -o dump1090 dump1090.o anet.o $(LDFLAGS) $(LDLIBS) +$(PROGNAME): $(PROGNAME).o anet.o + $(CC) -g -o $@ $^ $(LDFLAGS) $(LDLIBS) clean: - rm -f *.o dump1090 + rm -f *.o $(PROGNAME) diff --git a/dump1090.c b/dump1090.c index 8e84a60ac..dfd86842e 100644 --- a/dump1090.c +++ b/dump1090.c @@ -2,6 +2,9 @@ * * Copyright (C) 2012 by Salvatore Sanfilippo * + * HackRF One support added by Ilker Temir + * AirSpy support added by Chris Kuethe + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +48,12 @@ #include #include #include "rtl-sdr.h" +#include "libhackrf/hackrf.h" +#include "libairspy/airspy.h" +#ifndef NoSDRplay +#include "mirsdrapi-rsp.h" +#endif +#include "soxr.h" #include "anet.h" #define MODES_DEFAULT_RATE 2000000 @@ -54,6 +64,14 @@ #define MODES_DATA_LEN (16*16384) /* 256k */ #define MODES_AUTO_GAIN -100 /* Use automatic gain. */ #define MODES_MAX_GAIN 999999 /* Use max available gain. */ +/* HackRF One Defaults */ +#define HACKRF_RF_GAIN 0 +#define HACKRF_LNA_GAIN 32 +#define HACKRF_VGA_GAIN 48 +/* AirSpy defaults */ +#define AIRSPY_RF_GAIN 11 +#define AIRSPY_LNA_GAIN 11 +#define AIRSPY_VGA_GAIN 11 #define MODES_PREAMBLE_US 8 /* microseconds */ #define MODES_LONG_MSG_BITS 112 @@ -117,6 +135,7 @@ struct aircraft { int odd_cprlon; int even_cprlat; int even_cprlon; + int csv_logged; /* Value is 1 if already logged. */ double lat, lon; /* Coordinated obtained from CPR encoded data. */ long long odd_cprtime, even_cprtime; struct aircraft *next; /* Next aircraft in our linked list. */ @@ -137,11 +156,45 @@ struct { uint16_t *maglut; /* I/Q -> Magnitude lookup table. */ int exit; /* Exit from the main loop when true. */ + /* Drivers */ + int prefer_airspy; + int prefer_hackrf; + int prefer_rtlsdr; +#ifndef NoSDRplay + int prefer_sdrplay; +#endif + /* RTLSDR */ + int rtl_enabled; int dev_index; int gain; int enable_agc; rtlsdr_dev_t *dev; + + /* HackRF One and Airspy are very similar... */ + int hackrf_enabled; + int rf_gain; + int lna_gain; + int vga_gain; + int power_antenna; + hackrf_device *hackrf; + + /* ... but AirSpy needs to be resampled */ + int airspy_enabled; + struct airspy_device *airspy; + soxr_t resampler; + char *airspy_bytes, *airspy_scratch; + int support_10MSPS; + +#ifndef NoSDRplay + /* SDRplay */ + int sdrplay_enabled; + int sdrplaySamplesPerPacket; + short *sdrplay_i; + short *sdrplay_q; +#endif + + /* SDR Common */ int freq; /* Networking */ @@ -155,7 +208,6 @@ struct { /* Configuration */ char *filename; /* Input form file, --ifile option. */ - int loop; /* Read input file again and again. */ int fix_errors; /* Single bit error correction if true. */ int check_crc; /* Only display messages with good CRC. */ int raw; /* Raw output format. */ @@ -165,6 +217,7 @@ struct { int interactive; /* Interactive mode */ int interactive_rows; /* Interactive mode: max number of rows. */ int interactive_ttl; /* Interactive mode: TTL before deletion. */ + int csv_log; /* Log aircraft detection to CSV file. */ int stats; /* Print stats at exit in --ifile mode. */ int onlyaddr; /* Print only ICAO addresses. */ int metric; /* Use metric units. */ @@ -261,6 +314,10 @@ void modesInitConfig(void) { Modes.gain = MODES_MAX_GAIN; Modes.dev_index = 0; Modes.enable_agc = 0; + Modes.rf_gain = 0; + Modes.lna_gain = 0; + Modes.vga_gain = 0; + Modes.power_antenna = 0; Modes.freq = MODES_DEFAULT_FREQ; Modes.filename = NULL; Modes.fix_errors = 1; @@ -273,9 +330,10 @@ void modesInitConfig(void) { Modes.interactive = 0; Modes.interactive_rows = MODES_INTERACTIVE_ROWS; Modes.interactive_ttl = MODES_INTERACTIVE_TTL; + Modes.csv_log = 0; Modes.aggressive = 0; Modes.interactive_rows = getTermRows(); - Modes.loop = 0; + Modes.support_10MSPS = 0; } void modesInit(void) { @@ -333,7 +391,7 @@ void modesInit(void) { /* =============================== RTLSDR handling ========================== */ -void modesInitRTLSDR(void) { +int modesInitRTLSDR(void) { int j; int device_count; int ppm_error = 0; @@ -342,7 +400,7 @@ void modesInitRTLSDR(void) { device_count = rtlsdr_get_device_count(); if (!device_count) { fprintf(stderr, "No supported RTLSDR devices found.\n"); - exit(1); + return(1); } fprintf(stderr, "Found %d device(s):\n", device_count); @@ -355,7 +413,7 @@ void modesInitRTLSDR(void) { if (rtlsdr_open(&Modes.dev, Modes.dev_index) < 0) { fprintf(stderr, "Error opening the RTLSDR device: %s\n", strerror(errno)); - exit(1); + return(1); } /* Set gain, frequency, sample rate, and reset the device. */ @@ -383,8 +441,231 @@ void modesInitRTLSDR(void) { rtlsdr_reset_buffer(Modes.dev); fprintf(stderr, "Gain reported by device: %.2f\n", rtlsdr_get_tuner_gain(Modes.dev)/10.0); + Modes.rtl_enabled = 1; + Modes.hackrf_enabled = 0; + Modes.airspy_enabled = 0; +#ifndef NoSDRplay + Modes.sdrplay_enabled = 0; +#endif + return (0); +} + +/* =============================== AirSpy handling ========================== */ +int modesInitAirSpy(void) { + #define AIRSPY_STATUS(status, message) \ + if (status != 0) { \ + fprintf(stderr, "%s\n", message); \ + airspy_close(Modes.airspy); \ + airspy_exit(); \ + return (1); \ + } \ + + int status; + soxr_error_t sox_err = NULL; + soxr_io_spec_t ios; + soxr_quality_spec_t qts; + soxr_runtime_spec_t rts; + + Modes.airspy_scratch = calloc(2*MODES_DATA_LEN, sizeof(int16_t)); + Modes.airspy_bytes = malloc(2*MODES_DATA_LEN); + if ((Modes.airspy_bytes == NULL) || (Modes.airspy_scratch == NULL)) + err(1, NULL); + + ios = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); + qts = soxr_quality_spec(SOXR_MQ, 0); + rts = soxr_runtime_spec(2); + + status = airspy_init(); + AIRSPY_STATUS(status, "airspy_init failed."); + + status = airspy_open(&Modes.airspy); + AIRSPY_STATUS(status, "No AirSpy compatible devices found."); + + // The initial airspy mini doesnot support 10MSPS, + // its supported samplerate is 6Msps, 3Msps + uint32_t count=0; + airspy_get_samplerates(Modes.airspy, &count, 0); + uint32_t supported_samplerates[10]={0}; //10 is enough + airspy_get_samplerates(Modes.airspy, supported_samplerates, count); + for(uint32_t i=0;i buffer_length; + /* HackRF One returns signed IQ values, convert them to unsigned */ + for (i = 0; i < len; i++) { + transfer->buffer[i] ^= (uint8_t)0x80; + } + if (len > MODES_DATA_LEN) len = MODES_DATA_LEN; + /* Move the last part of the previous buffer, that was not processed, + * on the start of the new buffer. */ + memcpy(Modes.data, Modes.data+MODES_DATA_LEN, (MODES_FULL_LEN-1)*4); + /* Read the new data. */ + memcpy(Modes.data+(MODES_FULL_LEN-1)*4, transfer->buffer, len); + Modes.data_ready = 1; + /* Signal to the other thread that new data is ready */ + pthread_cond_signal(&Modes.data_cond); + pthread_mutex_unlock(&Modes.data_mutex); + return (0); +} + +int airspyCallback (airspy_transfer *transfer) { + pthread_mutex_lock(&Modes.data_mutex); + int16_t *inptr = (int16_t *)transfer->samples; + int16_t *outptr = (int16_t *)Modes.airspy_scratch; + size_t i, i_done, o_done, i_len, len; + + i_len = transfer->sample_count; + if(Modes.support_10MSPS) + { + len = 4 * i_len / 5; // downsample from 2.5Msps to 2Msps + } + else + { + len = 2 * i_len / 3; // downsample from 3Msps to 2Msps + } + + soxr_process(Modes.resampler, inptr, i_len, &i_done, outptr, len, &o_done); + for(i = 0; i < o_done; i++) + Modes.airspy_bytes[i] = (int8_t)(outptr[i]>>4)+127; + len = o_done; + if (len > MODES_DATA_LEN) len = MODES_DATA_LEN; + /* Move the last part of the previous buffer, that was not processed, + * on the start of the new buffer. */ + memcpy(Modes.data, Modes.data+MODES_DATA_LEN, (MODES_FULL_LEN-1)*4); + /* Read the new data. */ + memcpy(Modes.data+(MODES_FULL_LEN-1)*4, Modes.airspy_bytes, len); + Modes.data_ready = 1; + /* Signal to the other thread that new data is ready */ + pthread_cond_signal(&Modes.data_cond); + pthread_mutex_unlock(&Modes.data_mutex); + return (0); +} + /* This is used when --ifile is specified in order to read data from file * instead of using an RTLSDR device. */ void readDataFromFile(void) { @@ -435,16 +770,6 @@ void readDataFromFile(void) { p = Modes.data+(MODES_FULL_LEN-1)*4; while(toread) { nread = read(Modes.fd, p, toread); - /* In --file mode, seek the file again from the start - * and re-play it if --loop was given. */ - if (nread == 0 && - Modes.filename != NULL && - Modes.fd != STDIN_FILENO && - Modes.loop) - { - if (lseek(Modes.fd,0,SEEK_SET) != -1) continue; - } - if (nread <= 0) { Modes.exit = 1; /* Signal the other thread to exit. */ break; @@ -463,15 +788,111 @@ void readDataFromFile(void) { } } +#ifndef NoSDRplay +int sdrplay_start_rx(void) { + unsigned int data_index, firstSampleNum; + int grChanged, rfChanged, fsChanged; + int input_index = Modes.sdrplaySamplesPerPacket; + mir_sdr_ErrT err = 0; + + pthread_mutex_lock(&Modes.data_mutex); + while(1) + { + + if (Modes.data_ready) { + pthread_cond_wait(&Modes.data_cond,&Modes.data_mutex); + continue; + } + + /* Move the last part of the previous buffer, that was not processed, + * on the start of the new buffer. */ + + memcpy(Modes.magnitude, Modes.magnitude+MODES_DATA_LEN, (MODES_FULL_LEN-1)*4); + + /* now read new data buffer */ + + data_index = (MODES_FULL_LEN-1)*2; + while (data_index < ((MODES_DATA_LEN/2) + (MODES_FULL_LEN-1)*2)) + { + /* copy available data into buffer */ + + while ((data_index < (MODES_DATA_LEN/2 + (MODES_FULL_LEN-1)*2)) && (input_index < Modes.sdrplaySamplesPerPacket)) + { + int sum = abs(Modes.sdrplay_i[input_index++]); + sum += abs(Modes.sdrplay_i[input_index++]); + sum += abs(Modes.sdrplay_i[input_index++]); + sum += abs(Modes.sdrplay_i[input_index++]); + sum = sum >> 2; + if (sum > 32767) sum = 32767; + Modes.magnitude[data_index++] = sum; + } + + if (input_index > Modes.sdrplaySamplesPerPacket) { + fprintf(stderr, "ERROR packet size not divisible by 4\n"); + Modes.exit = 1; /* Signal the other thread to exit. */ + break; + } + + + if (input_index == Modes.sdrplaySamplesPerPacket) + { + input_index = 0; + err = mir_sdr_ReadPacket (Modes.sdrplay_i, Modes.sdrplay_q, + &firstSampleNum, &grChanged, &rfChanged, &fsChanged); + + if (err){ + fprintf(stderr, "sdrplay data read failed\n"); + Modes.exit = 1; /* Signal the other thread to exit. */ + break; + } + } + } + + Modes.data_ready = 1; + /* Signal to the other thread that new data is ready */ + pthread_cond_signal(&Modes.data_cond); + } + return (err)? 1 : 0; +} +#endif + /* We read data using a thread, so the main thread only handles decoding * without caring about data acquisition. */ void *readerThreadEntryPoint(void *arg) { MODES_NOTUSED(arg); if (Modes.filename == NULL) { - rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL, + if (Modes.rtl_enabled) { + rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL, MODES_ASYNC_BUF_NUMBER, MODES_DATA_LEN); + } else if (Modes.hackrf_enabled) { + int status = hackrf_start_rx(Modes.hackrf, hackrfCallback, NULL); + if (status != 0) { + fprintf(stderr, "hackrf_start_rx failed"); + hackrf_close(Modes.hackrf); + hackrf_exit(); + exit (1); + } + } else if (Modes.airspy_enabled) { + int status = airspy_start_rx(Modes.airspy, airspyCallback, NULL); + if (status != 0) { + fprintf(stderr, "airspy_start_rx failed"); + airspy_close(Modes.airspy); + airspy_exit(); + exit (1); + } + } +#ifndef NoSDRplay + else if (Modes.sdrplay_enabled) { + int status = sdrplay_start_rx(); + if (status != 0) { + fprintf(stderr, "sdrplay_start_rx failed"); + mir_sdr_Uninit(); + exit (1); + } + } +#endif } else { readDataFromFile(); } @@ -502,18 +923,10 @@ void dumpMagnitudeBar(int index, int magnitude) { buf[div] = set[rem]; buf[div+1] = '\0'; - if (index >= 0) { - int markchar = ']'; - - /* preamble peaks are marked with ">" */ - if (index == 0 || index == 2 || index == 7 || index == 9) - markchar = '>'; - /* Data peaks are marked to distinguish pairs of bits. */ - if (index >= 16) markchar = ((index-16)/2 & 1) ? '|' : ')'; - printf("[%.3d%c |%-66s %d\n", index, markchar, buf, magnitude); - } else { + if (index >= 0) + printf("[%.3d] |%-66s %d\n", index, buf, magnitude); + else printf("[%.2d] |%-66s %d\n", index, buf, magnitude); - } } /* Display an ASCII-art alike graphical representation of the undecoded @@ -1242,6 +1655,8 @@ void displayModesMessage(struct modesMessage *mm) { } } +float buf[16384]; + /* Turn I/Q samples pointed by Modes.data into the magnitude vector * pointed by Modes.magnitude. */ void computeMagnitudeVector(void) { @@ -1259,6 +1674,15 @@ void computeMagnitudeVector(void) { if (q < 0) q = -q; m[j/2] = Modes.maglut[i*129+q]; } + +#ifdef XX +{ +static FILE *fdump = NULL; int i; +if (fdump == NULL) fdump = fopen ("fdump", "w"); +for (i = 0; i < 16384; i++) { buf[i] = m[i]; } +fwrite (buf, sizeof(float), 16384, fdump); +} +#endif } /* Return -1 if the message is out of fase left-side @@ -1782,6 +2206,7 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { a->seen = time(NULL); a->messages++; + a->csv_logged = 0; if (mm->msgtype == 0 || mm->msgtype == 4 || mm->msgtype == 20) { a->altitude = mm->altitude; @@ -1801,7 +2226,8 @@ struct aircraft *interactiveReceiveData(struct modesMessage *mm) { } /* If the two data is less than 10 seconds apart, compute * the position. */ - if (abs(a->even_cprtime - a->odd_cprtime) <= 10000) { + int x = a->even_cprtime - a->odd_cprtime; + if (-10000 <= x && x <= 10000) { decodeCPR(a); } } else if (mm->metype == 19) { @@ -1849,6 +2275,44 @@ void interactiveShowData(void) { } } +/* Write aircraft detection logs as CSV file. */ +void writeCSVLog(void) { + struct aircraft *a = Modes.aircrafts; + FILE *log_file; + + if (NULL == (log_file = fopen("aircraft_log.csv", "a+"))) { + printf("Error opening aircraft_log.csv"); + return; + } + + fseek(log_file, 0, SEEK_END); + + if (ftell(log_file) == 0) { + fprintf(log_file, "Hex,Flight,Altitude,Speed,Lat,Lon,Track,Messages,Seen\n"); + } + + while(a) { + int altitude = a->altitude, speed = a->speed; + + /* Convert units to metric if --metric was specified. */ + if (Modes.metric) { + altitude /= 3.2828; + speed *= 1.852; + } + + if (a->csv_logged == 0) { + fprintf(log_file, "%s,%s,%d,%d,%f,%f,%d,%ld,%ld\n", + a->hexaddr, a->flight, altitude, speed, + a->lat, a->lon, a->track, a->messages, + a->seen); + a->csv_logged = 1; + } + a = a->next; + } + + fclose(log_file); +} + /* When in interactive mode If we don't receive new nessages within * MODES_INTERACTIVE_TTL seconds we remove the aircraft from the list. */ void interactiveRemoveStaleAircrafts(void) { @@ -2439,11 +2903,28 @@ int getTermRows() { void showHelp(void) { printf( "--device-index Select RTL device (default: 0).\n" -"--gain Set gain (default: max gain. Use -100 for auto-gain).\n" -"--enable-agc Enable the Automatic Gain Control (default: off).\n" +"--dev-rtl use RTLSDR device.\n" +"--dev-hackrf use HackRF device.\n" +"--dev-airspy use AirSpy device.\n" +#ifndef NoSDRplay +"--dev-sdrplay use RSP device.\n" +#endif +"--gain Set RTLSDR gain (default: max gain. Use -100 for auto-gain).\n" +"--enable-agc Enable RTLSDR Automatic Gain Control (default: off).\n" +"--enable-amp Enable HackRF RX/TX RF amplifier (default: off).\n" +"--enable-antenna Enable HackRF antenna port power (default: off)\n" +"--rf-gain Set RX AMP (RF) gain\n" +" HackRF 0 or 14, default 0\n" +" AirSpy 0-14, step 1, default 11\n" +"--lna-gain Set RX LNA (IF) gain\n" +" HackRF 0-40, step 8, default: 40\n" +" AirSpy 0-14, step 1, default: 11\n" +"--vga-gain Set RX VGA (baseband) gain\n" +" HackRF 0-62, step 2, default: 62\n" +" AirSpy 0-14, step 1, default: 11\n" "--freq Set frequency (default: 1090 Mhz).\n" "--ifile Read data from file (use '-' for stdin).\n" -"--loop With --ifile, read the same file in a loop.\n" +"--csv-log Log data to aircraft_log.csv for later analysis.\n" "--interactive Interactive mode refreshing data on screen.\n" "--interactive-rows Max number of rows in interactive mode (default: 15).\n" "--interactive-ttl Remove from list if idle for (default: 60).\n" @@ -2484,6 +2965,11 @@ void backgroundTasks(void) { interactiveRemoveStaleAircrafts(); } + /* Log to CSV if CSV logging is activated. */ + if (Modes.csv_log == 1) { + writeCSVLog(); + } + /* Refresh screen when in interactive mode. */ if (Modes.interactive && (mstime() - Modes.interactive_last_update) > @@ -2495,9 +2981,20 @@ void backgroundTasks(void) { } } +void INTHandler(int sig) +{ + signal(sig, SIG_IGN); +#ifndef NoSDRplay + mir_sdr_Uninit(); +#endif + exit(0); +} + int main(int argc, char **argv) { int j; + signal(SIGINT, INTHandler); + /* Set sane defaults. */ modesInitConfig(); @@ -2507,16 +3004,42 @@ int main(int argc, char **argv) { if (!strcmp(argv[j],"--device-index") && more) { Modes.dev_index = atoi(argv[++j]); + } +#ifndef NoSDRplay + else if (!strcmp(argv[j],"--dev-sdrplay")) { + Modes.prefer_sdrplay = 1; + } +#endif + else if (!strcmp(argv[j],"--dev-airspy")) { + Modes.rf_gain = AIRSPY_RF_GAIN; + Modes.lna_gain = AIRSPY_LNA_GAIN; + Modes.vga_gain = AIRSPY_VGA_GAIN; + Modes.prefer_airspy = 1; + } else if (!strcmp(argv[j],"--dev-hackrf")) { + Modes.rf_gain = HACKRF_RF_GAIN; + Modes.lna_gain = HACKRF_LNA_GAIN; + Modes.vga_gain = HACKRF_VGA_GAIN; + Modes.prefer_hackrf = 1; + } else if (!strcmp(argv[j],"--dev-rtlsdr")) { + Modes.prefer_rtlsdr = 1; } else if (!strcmp(argv[j],"--gain") && more) { Modes.gain = atof(argv[++j])*10; /* Gain is in tens of DBs */ } else if (!strcmp(argv[j],"--enable-agc")) { Modes.enable_agc++; + } else if (!strcmp(argv[j],"--enable-amp")) { + Modes.rf_gain = 14; + } else if (!strcmp(argv[j],"--enable-antenna")) { + Modes.power_antenna = 1; + } else if (!strcmp(argv[j],"--rf-gain")) { + Modes.rf_gain = atoi(argv[++j]); + } else if (!strcmp(argv[j],"--lna-gain")) { + Modes.lna_gain = atoi(argv[++j]); + } else if (!strcmp(argv[j],"--vga-gain")) { + Modes.vga_gain = atoi(argv[++j]); } else if (!strcmp(argv[j],"--freq") && more) { Modes.freq = strtoll(argv[++j],NULL,10); } else if (!strcmp(argv[j],"--ifile") && more) { Modes.filename = strdup(argv[++j]); - } else if (!strcmp(argv[j],"--loop")) { - Modes.loop = 1; } else if (!strcmp(argv[j],"--no-fix")) { Modes.fix_errors = 0; } else if (!strcmp(argv[j],"--no-crc-check")) { @@ -2542,6 +3065,8 @@ int main(int argc, char **argv) { Modes.metric = 1; } else if (!strcmp(argv[j],"--aggressive")) { Modes.aggressive++; + } else if (!strcmp(argv[j],"--csv-log")) { + Modes.csv_log = 1; } else if (!strcmp(argv[j],"--interactive")) { Modes.interactive = 1; } else if (!strcmp(argv[j],"--interactive-rows")) { @@ -2583,6 +3108,20 @@ int main(int argc, char **argv) { } } + if ((Modes.prefer_airspy + Modes.prefer_hackrf + Modes.prefer_rtlsdr +#ifndef NoSDRplay + + Modes.prefer_sdrplay +#endif + ) > 1) { + showHelp(); + fprintf(stderr, "\n\nError: dev-{" +#ifndef NoSDRplay + "sdrplay," +#endif + "airspy,hackrf,rtlsdr} are mutually exclusive.\n"); + exit(1); + } + /* Setup for SIGWINCH for handling lines */ if (Modes.interactive == 1) signal(SIGWINCH, sigWinchCallback); @@ -2591,7 +3130,34 @@ int main(int argc, char **argv) { if (Modes.net_only) { fprintf(stderr,"Net-only mode, no RTL device or file open.\n"); } else if (Modes.filename == NULL) { - modesInitRTLSDR(); + if ((Modes.prefer_airspy + Modes.prefer_hackrf +#ifndef NoSDRplay + + Modes.prefer_sdrplay +#endif + ) == 0 && modesInitRTLSDR() == 0) { + Modes.rtl_enabled = 1; + } +#ifndef NoSDRplay + else if ((Modes.prefer_hackrf + Modes.prefer_airspy + Modes.prefer_rtlsdr ) == 0 && modesInitSDRplay() == 0 ) { + Modes.sdrplay_enabled = 1; + } +#endif + else if (( +#ifndef NoSDRplay + Modes.prefer_sdrplay + +#endif + Modes.prefer_airspy + Modes.prefer_rtlsdr ) == 0 && modesInitHackRF() == 0 ) { + Modes.hackrf_enabled = 1; + } else if (( +#ifndef NoSDRplay + Modes.prefer_sdrplay + +#endif + Modes.prefer_rtlsdr + Modes.prefer_hackrf ) == 0 && modesInitAirSpy() == 0 ) { + Modes.airspy_enabled = 1; + } else { + fprintf(stderr,"No compatible SDR device found.\n"); + exit (1); + } } else { if (Modes.filename[0] == '-' && Modes.filename[1] == '\0') { Modes.fd = STDIN_FILENO; @@ -2656,4 +3222,3 @@ int main(int argc, char **argv) { return 0; } - From 7015b6509f969214b9215e3706267673ac093b20 Mon Sep 17 00:00:00 2001 From: Doolan_R Date: Fri, 25 Nov 2022 08:39:44 +0000 Subject: [PATCH 2/2] add hackrf --- build_libs.txt | 27 +++++++++++++++++++++++++++ images/dump1090_sdrplus.png | Bin 0 -> 258323 bytes 2 files changed, 27 insertions(+) create mode 100644 build_libs.txt create mode 100644 images/dump1090_sdrplus.png diff --git a/build_libs.txt b/build_libs.txt new file mode 100644 index 000000000..678c00760 --- /dev/null +++ b/build_libs.txt @@ -0,0 +1,27 @@ +To build RTL-SDR, HackRF and Airspy librares use the relevant git statements below and then the same build sequence of... + +cd +mkdir build +cd build +cmake ../ +make +sudo make install +sudo ldconfig + +RTL-SDR: git clone git//git.osmocom.org/rtl-sdr.git ./rtl-sdr +HACKRF: git clone https://github.com/mossmann/hackrf/host.git ./hackrf +AIRSPY: git clone https://github.com/airspy/host.git ./airspy + +For Soxr: + +git clone https://github.com/uklauer/soxr.git ./soxr + +then... + +cd soxr +./go +cd Release +sudo make install + +wget https://www.sdrplay.com/software/SDRplay_RSP_API-RPi-2.13.1.run +sh ./SDRplay_RSP_API-RPi-2.13.1.run diff --git a/images/dump1090_sdrplus.png b/images/dump1090_sdrplus.png new file mode 100644 index 0000000000000000000000000000000000000000..4b4302bde3ec7e0efcca3abec7586bfd77bcf8b6 GIT binary patch literal 258323 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