|
|
@ -50,8 +50,8 @@ |
|
|
|
|
|
|
|
|
|
|
|
#define ADSB_RATE 2000000 |
|
|
|
#define ADSB_RATE 2000000 |
|
|
|
#define ADSB_FREQ 1090000000 |
|
|
|
#define ADSB_FREQ 1090000000 |
|
|
|
#define DEFAULT_ASYNC_BUF_NUMBER 32 |
|
|
|
#define DEFAULT_ASYNC_BUF_NUMBER 12 |
|
|
|
#define DEFAULT_BUF_LENGTH (128 * 16384) |
|
|
|
#define DEFAULT_BUF_LENGTH (16 * 16384) |
|
|
|
#define AUTO_GAIN -100 |
|
|
|
#define AUTO_GAIN -100 |
|
|
|
|
|
|
|
|
|
|
|
static pthread_t demod_thread; |
|
|
|
static pthread_t demod_thread; |
|
|
@ -61,8 +61,9 @@ static rtlsdr_dev_t *dev = NULL; |
|
|
|
|
|
|
|
|
|
|
|
/* todo, bundle these up in a struct */ |
|
|
|
/* todo, bundle these up in a struct */ |
|
|
|
uint8_t *buffer; |
|
|
|
uint8_t *buffer; |
|
|
|
int raw_output = 0; |
|
|
|
int verbose_output = 0; |
|
|
|
int short_output = 0; |
|
|
|
int short_output = 0; |
|
|
|
|
|
|
|
double quality = 1.0; |
|
|
|
int allowed_errors = 5; |
|
|
|
int allowed_errors = 5; |
|
|
|
FILE *file; |
|
|
|
FILE *file; |
|
|
|
int adsb_frame[14]; |
|
|
|
int adsb_frame[14]; |
|
|
@ -76,16 +77,17 @@ void usage(void) |
|
|
|
"rtl_adsb, a simple ADS-B decoder\n\n" |
|
|
|
"rtl_adsb, a simple ADS-B decoder\n\n" |
|
|
|
"Use:\trtl_adsb [-R] [-g gain] [-p ppm] [output file]\n" |
|
|
|
"Use:\trtl_adsb [-R] [-g gain] [-p ppm] [output file]\n" |
|
|
|
"\t[-d device_index (default: 0)]\n" |
|
|
|
"\t[-d device_index (default: 0)]\n" |
|
|
|
"\t[-R output raw bitstream (default: off)]\n" |
|
|
|
"\t[-V verbove output (default: off)]\n" |
|
|
|
"\t[-S show short frames (default: off)]\n" |
|
|
|
"\t[-S show short frames (default: off)]\n" |
|
|
|
|
|
|
|
"\t[-Q quality (0: no sanity checks, 0.5: half bit, 1: one bit (default), 2: two bits)]\n" |
|
|
|
"\t[-e allowed_errors (default: 5)]\n" |
|
|
|
"\t[-e allowed_errors (default: 5)]\n" |
|
|
|
"\t[-g tuner_gain (default: automatic)]\n" |
|
|
|
"\t[-g tuner_gain (default: automatic)]\n" |
|
|
|
"\t[-p ppm_error (default: 0)]\n" |
|
|
|
"\t[-p ppm_error (default: 0)]\n" |
|
|
|
"\tfilename (a '-' dumps samples to stdout)\n" |
|
|
|
"\tfilename (a '-' dumps samples to stdout)\n" |
|
|
|
"\t (omitting the filename also uses stdout)\n\n" |
|
|
|
"\t (omitting the filename also uses stdout)\n\n" |
|
|
|
"Streaming with netcat:\n" |
|
|
|
"Streaming with netcat:\n" |
|
|
|
"\trtl_adsb -R | netcat -lp 8080\n" |
|
|
|
"\trtl_adsb | netcat -lp 8080\n" |
|
|
|
"\twhile true; do rtl_adsb -R | nc -lp 8080; done\n" |
|
|
|
"\twhile true; do rtl_adsb | nc -lp 8080; done\n" |
|
|
|
"\n"); |
|
|
|
"\n"); |
|
|
|
exit(1); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
} |
|
|
@ -113,23 +115,25 @@ static void sighandler(int signum) |
|
|
|
|
|
|
|
|
|
|
|
void display(int *frame, int len) |
|
|
|
void display(int *frame, int len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i; |
|
|
|
int i, df; |
|
|
|
if (!short_output && len <= short_frame) { |
|
|
|
if (!short_output && len <= short_frame) { |
|
|
|
return;} |
|
|
|
return;} |
|
|
|
if (raw_output) { |
|
|
|
df = (frame[0] >> 3) & 0x1f; |
|
|
|
|
|
|
|
if (quality == 0.0 && !(df==11 || df==17 || df==18 || df==19)) { |
|
|
|
|
|
|
|
return;} |
|
|
|
fprintf(file, "*"); |
|
|
|
fprintf(file, "*"); |
|
|
|
for (i=0; i<((len+7)/8); i++) { |
|
|
|
for (i=0; i<((len+7)/8); i++) { |
|
|
|
fprintf(file, "%02x", frame[i]);} |
|
|
|
fprintf(file, "%02x", frame[i]);} |
|
|
|
fprintf(file, ";\r\n"); |
|
|
|
fprintf(file, ";\r\n"); |
|
|
|
return; |
|
|
|
if (!verbose_output) { |
|
|
|
} |
|
|
|
return;} |
|
|
|
fprintf(file, "----------\n"); |
|
|
|
fprintf(file, "DF=%i CA=%i\n", df, frame[0] & 0x07); |
|
|
|
fprintf(file, "DF=%x CA=%x\n", (frame[0] >> 3) & 0x1f, frame[0] & 0x07); |
|
|
|
|
|
|
|
fprintf(file, "ICAO Address=%06x\n", frame[1] << 16 | frame[2] << 8 | frame[3]); |
|
|
|
fprintf(file, "ICAO Address=%06x\n", frame[1] << 16 | frame[2] << 8 | frame[3]); |
|
|
|
if (len <= short_frame) { |
|
|
|
if (len <= short_frame) { |
|
|
|
return;} |
|
|
|
return;} |
|
|
|
fprintf(file, "PI=0x%06x\n", frame[11] << 16 | frame[12] << 8 | frame[13]); |
|
|
|
fprintf(file, "PI=0x%06x\n", frame[11] << 16 | frame[12] << 8 | frame[13]); |
|
|
|
fprintf(file, "Type Code=%x S.Type/Ant.=%x\n", (frame[4] >> 3) & 0x1f, frame[4] & 0x07); |
|
|
|
fprintf(file, "Type Code=%i S.Type/Ant.=%x\n", (frame[4] >> 3) & 0x1f, frame[4] & 0x07); |
|
|
|
|
|
|
|
fprintf(file, "--------------\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int magnitute(unsigned char *buf, int len) |
|
|
|
int magnitute(unsigned char *buf, int len) |
|
|
@ -151,6 +155,30 @@ inline unsigned char single_manchester(unsigned char a, unsigned char b, unsigne |
|
|
|
int bit, bit_p; |
|
|
|
int bit, bit_p; |
|
|
|
bit_p = a > b; |
|
|
|
bit_p = a > b; |
|
|
|
bit = c > d; |
|
|
|
bit = c > d; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (quality == 0.0) { |
|
|
|
|
|
|
|
return bit;} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (quality == 0.5) { |
|
|
|
|
|
|
|
if ( bit && bit_p && b > c) { |
|
|
|
|
|
|
|
return 255;} |
|
|
|
|
|
|
|
if (!bit && !bit_p && b < c) { |
|
|
|
|
|
|
|
return 255;} |
|
|
|
|
|
|
|
return bit; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (quality == 1.0) { |
|
|
|
|
|
|
|
if ( bit && bit_p && c > b) { |
|
|
|
|
|
|
|
return 1;} |
|
|
|
|
|
|
|
if ( bit && !bit_p && d < b) { |
|
|
|
|
|
|
|
return 1;} |
|
|
|
|
|
|
|
if (!bit && bit_p && d > b) { |
|
|
|
|
|
|
|
return 0;} |
|
|
|
|
|
|
|
if (!bit && !bit_p && c < b) { |
|
|
|
|
|
|
|
return 0;} |
|
|
|
|
|
|
|
return 255; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ( bit && bit_p && c > b && d < a) { |
|
|
|
if ( bit && bit_p && c > b && d < a) { |
|
|
|
return 1;} |
|
|
|
return 1;} |
|
|
|
if ( bit && !bit_p && c > a && d < b) { |
|
|
|
if ( bit && !bit_p && c > a && d < b) { |
|
|
@ -184,10 +212,12 @@ inline int preamble(unsigned char *buf, int len, int i) |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
case 7: |
|
|
|
case 7: |
|
|
|
case 9: |
|
|
|
case 9: |
|
|
|
high = min(high, buf[i+i2]); |
|
|
|
//high = min(high, buf[i+i2]);
|
|
|
|
|
|
|
|
high = buf[i+i2]; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
low = max(low, buf[i+i2]); |
|
|
|
//low = max(low, buf[i+i2]);
|
|
|
|
|
|
|
|
low = buf[i+i2]; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (high <= low) { |
|
|
|
if (high <= low) { |
|
|
@ -215,7 +245,6 @@ void manchester(unsigned char *buf, int len) |
|
|
|
for (i2=0; i2<preamble_len; i2++) { |
|
|
|
for (i2=0; i2<preamble_len; i2++) { |
|
|
|
buf[i+i2] = 253;} |
|
|
|
buf[i+i2] = 253;} |
|
|
|
i += preamble_len; |
|
|
|
i += preamble_len; |
|
|
|
//printf("preamble found\n");
|
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
i2 = start = i; |
|
|
|
i2 = start = i; |
|
|
@ -231,7 +260,8 @@ void manchester(unsigned char *buf, int len) |
|
|
|
buf[i2] = 255; |
|
|
|
buf[i2] = 255; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
bit = 0; |
|
|
|
bit = a > b; |
|
|
|
|
|
|
|
/* these don't have to match the bit */ |
|
|
|
a = 0; |
|
|
|
a = 0; |
|
|
|
b = 255; |
|
|
|
b = 255; |
|
|
|
} |
|
|
|
} |
|
|
@ -239,8 +269,6 @@ void manchester(unsigned char *buf, int len) |
|
|
|
buf[i] = buf[i+1] = 254; /* to be overwritten */ |
|
|
|
buf[i] = buf[i+1] = 254; /* to be overwritten */ |
|
|
|
buf[i2] = bit; |
|
|
|
buf[i2] = bit; |
|
|
|
} |
|
|
|
} |
|
|
|
// todo, nuke short segments
|
|
|
|
|
|
|
|
//printf("%i\n", i2 - start);
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -263,18 +291,16 @@ void messages(unsigned char *buf, int len) |
|
|
|
adsb_frame[index] |= (unsigned char)(1<<shift); |
|
|
|
adsb_frame[index] |= (unsigned char)(1<<shift); |
|
|
|
} |
|
|
|
} |
|
|
|
if (data_i == 7) { |
|
|
|
if (data_i == 7) { |
|
|
|
//if (adsb_frame[0] == 0) {
|
|
|
|
if (adsb_frame[0] == 0) { |
|
|
|
// break;}
|
|
|
|
break;} |
|
|
|
if (adsb_frame[0] & 0x80) { |
|
|
|
if (adsb_frame[0] & 0x80) { |
|
|
|
frame_len = long_frame;} |
|
|
|
frame_len = long_frame;} |
|
|
|
else { |
|
|
|
else { |
|
|
|
frame_len = short_frame;} |
|
|
|
frame_len = short_frame;} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// todo, check CRC
|
|
|
|
|
|
|
|
if (data_i < (frame_len-1)) { |
|
|
|
if (data_i < (frame_len-1)) { |
|
|
|
continue;} |
|
|
|
continue;} |
|
|
|
//fprintf(file, "bits: %i\n", data_i);
|
|
|
|
|
|
|
|
display(adsb_frame, frame_len); |
|
|
|
display(adsb_frame, frame_len); |
|
|
|
fflush(file); |
|
|
|
fflush(file); |
|
|
|
} |
|
|
|
} |
|
|
@ -299,7 +325,6 @@ static void *demod_thread_fn(void *arg) |
|
|
|
len = magnitute(buffer, DEFAULT_BUF_LENGTH); |
|
|
|
len = magnitute(buffer, DEFAULT_BUF_LENGTH); |
|
|
|
manchester(buffer, len); |
|
|
|
manchester(buffer, len); |
|
|
|
messages(buffer, len); |
|
|
|
messages(buffer, len); |
|
|
|
//fsync(file);
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
rtlsdr_cancel_async(dev); |
|
|
|
rtlsdr_cancel_async(dev); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
@ -312,14 +337,14 @@ int main(int argc, char **argv) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
char *filename = NULL; |
|
|
|
char *filename = NULL; |
|
|
|
int n_read, r, opt; |
|
|
|
int n_read, r, opt; |
|
|
|
int i, gain = AUTO_GAIN; // tenths of a dB
|
|
|
|
int i, gain = AUTO_GAIN; /* tenths of a dB */ |
|
|
|
uint32_t dev_index = 0; |
|
|
|
uint32_t dev_index = 0; |
|
|
|
int device_count; |
|
|
|
int device_count; |
|
|
|
int ppm_error = 0; |
|
|
|
int ppm_error = 0; |
|
|
|
char vendor[256], product[256], serial[256]; |
|
|
|
char vendor[256], product[256], serial[256]; |
|
|
|
sem_init(&data_ready, 0, 0); |
|
|
|
sem_init(&data_ready, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
while ((opt = getopt(argc, argv, "g:p:e:RS")) != -1) |
|
|
|
while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1) |
|
|
|
{ |
|
|
|
{ |
|
|
|
switch (opt) { |
|
|
|
switch (opt) { |
|
|
|
case 'd': |
|
|
|
case 'd': |
|
|
@ -331,8 +356,8 @@ int main(int argc, char **argv) |
|
|
|
case 'p': |
|
|
|
case 'p': |
|
|
|
ppm_error = atoi(optarg); |
|
|
|
ppm_error = atoi(optarg); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'R': |
|
|
|
case 'V': |
|
|
|
raw_output = 1; |
|
|
|
verbose_output = 1; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'S': |
|
|
|
case 'S': |
|
|
|
short_output = 1; |
|
|
|
short_output = 1; |
|
|
@ -340,6 +365,9 @@ int main(int argc, char **argv) |
|
|
|
case 'e': |
|
|
|
case 'e': |
|
|
|
allowed_errors = atoi(optarg); |
|
|
|
allowed_errors = atoi(optarg); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'Q': |
|
|
|
|
|
|
|
quality = atof(optarg); |
|
|
|
|
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
usage(); |
|
|
|
usage(); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
@ -347,7 +375,6 @@ int main(int argc, char **argv) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (argc <= optind) { |
|
|
|
if (argc <= optind) { |
|
|
|
//usage();
|
|
|
|
|
|
|
|
filename = "-"; |
|
|
|
filename = "-"; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
filename = argv[optind]; |
|
|
|
filename = argv[optind]; |
|
|
|