Acurite minor bugfixes
[rtl-433.git] / src / rtl_adsb.c
1 /*
2  * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
3  * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
4  * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
5  * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
6  * Copyright (C) 2012 by Youssef Touil <youssef@sdrsharp.com>
7  * Copyright (C) 2012 by Ian Gilmour <ian@sdrsharp.com>
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include <errno.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
30
31 #ifndef _WIN32
32 #include <unistd.h>
33 #else
34 #include <Windows.h>
35 #include <fcntl.h>
36 #include <io.h>
37 #include "getopt/getopt.h"
38 #endif
39
40 #include <semaphore.h>
41 #include <pthread.h>
42 #include <libusb.h>
43
44 #include "rtl-sdr.h"
45
46 #ifdef _WIN32
47 #define sleep Sleep
48 #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))
49 #endif
50
51 #define ADSB_RATE                       2000000
52 #define ADSB_FREQ                       1090000000
53 #define DEFAULT_ASYNC_BUF_NUMBER        12
54 #define DEFAULT_BUF_LENGTH              (16 * 16384)
55 #define AUTO_GAIN                       -100
56
57 static pthread_t demod_thread;
58 static sem_t data_ready;
59 static volatile int do_exit = 0;
60 static rtlsdr_dev_t *dev = NULL;
61
62 /* look up table, could be made smaller */
63 uint8_t pyth[129][129];
64
65 /* todo, bundle these up in a struct */
66 uint8_t *buffer;
67 int verbose_output = 0;
68 int short_output = 0;
69 double quality = 1.0;
70 int allowed_errors = 5;
71 FILE *file;
72 int adsb_frame[14];
73 #define preamble_len            16
74 #define long_frame              112
75 #define short_frame             56
76
77 void usage(void)
78 {
79         fprintf(stderr,
80                 "rtl_adsb, a simple ADS-B decoder\n\n"
81                 "Use:\trtl_adsb [-R] [-g gain] [-p ppm] [output file]\n"
82                 "\t[-d device_index (default: 0)]\n"
83                 "\t[-V verbove output (default: off)]\n"
84                 "\t[-S show short frames (default: off)]\n"
85                 "\t[-Q quality (0: no sanity checks, 0.5: half bit, 1: one bit (default), 2: two bits)]\n"
86                 "\t[-e allowed_errors (default: 5)]\n"
87                 "\t[-g tuner_gain (default: automatic)]\n"
88                 "\t[-p ppm_error (default: 0)]\n"
89                 "\tfilename (a '-' dumps samples to stdout)\n"
90                 "\t (omitting the filename also uses stdout)\n\n"
91                 "Streaming with netcat:\n"
92                 "\trtl_adsb | netcat -lp 8080\n"
93                 "\twhile true; do rtl_adsb | nc -lp 8080; done\n"
94                 "Streaming with socat:\n"
95                 "\trtl_adsb | socat -u - TCP4:sdrsharp.com:47806\n"
96                 "\n");
97         exit(1);
98 }
99
100 #ifdef _WIN32
101 BOOL WINAPI
102 sighandler(int signum)
103 {
104         if (CTRL_C_EVENT == signum) {
105                 fprintf(stderr, "Signal caught, exiting!\n");
106                 do_exit = 1;
107                 rtlsdr_cancel_async(dev);
108                 return TRUE;
109         }
110         return FALSE;
111 }
112 #else
113 static void sighandler(int signum)
114 {
115         fprintf(stderr, "Signal caught, exiting!\n");
116         do_exit = 1;
117         rtlsdr_cancel_async(dev);
118 }
119 #endif
120
121 void display(int *frame, int len)
122 {
123         int i, df;
124         if (!short_output && len <= short_frame) {
125                 return;}
126         df = (frame[0] >> 3) & 0x1f;
127         if (quality == 0.0 && !(df==11 || df==17 || df==18 || df==19)) {
128                 return;}
129         fprintf(file, "*");
130         for (i=0; i<((len+7)/8); i++) {
131                 fprintf(file, "%02x", frame[i]);}
132         fprintf(file, ";\r\n");
133         if (!verbose_output) {
134                 return;}
135         fprintf(file, "DF=%i CA=%i\n", df, frame[0] & 0x07);
136         fprintf(file, "ICAO Address=%06x\n", frame[1] << 16 | frame[2] << 8 | frame[3]);
137         if (len <= short_frame) {
138                 return;}
139         fprintf(file, "PI=0x%06x\n",  frame[11] << 16 | frame[12] << 8 | frame[13]);
140         fprintf(file, "Type Code=%i S.Type/Ant.=%x\n", (frame[4] >> 3) & 0x1f, frame[4] & 0x07);
141         fprintf(file, "--------------\n");
142 }
143
144 void pyth_precompute(void)
145 {
146         int x, y;
147         double scale = 1.408 ;  /* use the full 8 bits */
148         for (x=0; x<129; x++) {
149         for (y=0; y<129; y++) {
150                 pyth[x][y] = (uint8_t)round(scale * sqrt(x*x + y*y));
151         }}
152 }
153
154 inline uint8_t abs8(uint8_t x)
155 /* do not subtract 128 from the raw iq, this handles it */
156 {
157         if (x >= 128) {
158                 return x - 128;}
159         return 128 - x;
160 }
161
162 int magnitute(uint8_t *buf, int len)
163 /* takes i/q, changes buf in place, returns new len */
164 {
165         int i;
166         for (i=0; i<len; i+=2) {
167                 buf[i/2] = pyth[abs8(buf[i])][abs8(buf[i+1])];
168         }
169         return len/2;
170 }
171
172 inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
173 /* takes 4 consecutive real samples, return 0 or 1, 255 on error */
174 {
175         int bit, bit_p;
176         bit_p = a > b;
177         bit   = c > d;
178
179         if (quality == 0.0) {
180                 return bit;}
181
182         if (quality == 0.5) {
183                 if ( bit &&  bit_p && b > c) {
184                         return 255;}
185                 if (!bit && !bit_p && b < c) {
186                         return 255;}
187                 return bit;
188         }
189
190         if (quality == 1.0) {
191                 if ( bit &&  bit_p && c > b) {
192                         return 1;}
193                 if ( bit && !bit_p && d < b) {
194                         return 1;}
195                 if (!bit &&  bit_p && d > b) {
196                         return 0;}
197                 if (!bit && !bit_p && c < b) {
198                         return 0;}
199                 return 255;
200         }
201
202         if ( bit &&  bit_p && c > b && d < a) {
203                 return 1;}
204         if ( bit && !bit_p && c > a && d < b) {
205                 return 1;}
206         if (!bit &&  bit_p && c < a && d > b) {
207                 return 0;}
208         if (!bit && !bit_p && c < b && d > a) {
209                 return 0;}
210         return 255;
211 }
212
213 inline uint8_t min8(uint8_t a, uint8_t b)
214 {
215         return a<b ? a : b;
216 }
217
218 inline uint8_t max8(uint8_t a, uint8_t b)
219 {
220         return a>b ? a : b;
221 }
222
223 inline int preamble(uint8_t *buf, int len, int i)
224 /* returns 0/1 for preamble at index i */
225 {
226         int i2;
227         uint8_t low  = 0;
228         uint8_t high = 255;
229         for (i2=0; i2<preamble_len; i2++) {
230                 switch (i2) {
231                         case 0:
232                         case 2:
233                         case 7:
234                         case 9:
235                                 //high = min8(high, buf[i+i2]);
236                                 high = buf[i+i2];
237                                 break;
238                         default:
239                                 //low  = max8(low,  buf[i+i2]);
240                                 low = buf[i+i2];
241                                 break;
242                 }
243                 if (high <= low) {
244                         return 0;}
245         }
246         return 1;
247 }
248
249 void manchester(uint8_t *buf, int len)
250 /* overwrites magnitude buffer with valid bits (255 on errors) */
251 {
252         /* a and b hold old values to verify local manchester */
253         uint8_t a=0, b=0;
254         uint8_t bit;
255         int i, i2, start, errors;
256         // todo, allow wrap across buffers
257         i = 0;
258         while (i < len) {
259                 /* find preamble */
260                 for ( ; i < (len - preamble_len); i++) {
261                         if (!preamble(buf, len, i)) {
262                                 continue;}
263                         a = buf[i];
264                         b = buf[i+1];
265                         for (i2=0; i2<preamble_len; i2++) {
266                                 buf[i+i2] = 253;}
267                         i += preamble_len;
268                         break;
269                 }
270                 i2 = start = i;
271                 errors = 0;
272                 /* mark bits until encoding breaks */
273                 for ( ; i < len; i+=2, i2++) {
274                         bit = single_manchester(a, b, buf[i], buf[i+1]);
275                         a = buf[i];
276                         b = buf[i+1];
277                         if (bit == 255) {
278                                 errors += 1;
279                                 if (errors > allowed_errors) {
280                                         buf[i2] = 255;
281                                         break;
282                                 } else {
283                                         bit = a > b;
284                                         /* these don't have to match the bit */
285                                         a = 0;
286                                         b = 255;
287                                 }
288                         }
289                         buf[i] = buf[i+1] = 254;  /* to be overwritten */
290                         buf[i2] = bit;
291                 }
292         }
293 }
294
295 void messages(uint8_t *buf, int len)
296 {
297         int i, i2, start, preamble_found;
298         int data_i, index, shift, frame_len;
299         // todo, allow wrap across buffers
300         for (i=0; i<len; i++) {
301                 if (buf[i] > 1) {
302                         continue;}
303                 frame_len = long_frame;
304                 data_i = 0;
305                 for (index=0; index<14; index++) {
306                         adsb_frame[index] = 0;}
307                 for(; i<len && buf[i]<=1 && data_i<frame_len; i++, data_i++) {
308                         if (buf[i]) {
309                                 index = data_i / 8;
310                                 shift = 7 - (data_i % 8);
311                                 adsb_frame[index] |= (uint8_t)(1<<shift);
312                         }
313                         if (data_i == 7) {
314                                 if (adsb_frame[0] == 0) {
315                                     break;}
316                                 if (adsb_frame[0] & 0x80) {
317                                         frame_len = long_frame;}
318                                 else {
319                                         frame_len = short_frame;}
320                         }
321                 }
322                 if (data_i < (frame_len-1)) {
323                         continue;}
324                 display(adsb_frame, frame_len);
325                 fflush(file);
326         }
327 }
328
329 static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
330 {
331         int dr_val;
332         if (do_exit) {
333                 return;}
334         memcpy(buffer, buf, len);
335         sem_getvalue(&data_ready, &dr_val);
336         if (dr_val <= 0) {
337                 sem_post(&data_ready);}
338 }
339
340 static void *demod_thread_fn(void *arg)
341 {
342         int len;
343         while (!do_exit) {
344                 sem_wait(&data_ready);
345                 len = magnitute(buffer, DEFAULT_BUF_LENGTH);
346                 manchester(buffer, len);
347                 messages(buffer, len);
348         }
349         rtlsdr_cancel_async(dev);
350         return 0;
351 }
352
353 int main(int argc, char **argv)
354 {
355 #ifndef _WIN32
356         struct sigaction sigact;
357 #endif
358         char *filename = NULL;
359         int n_read, r, opt;
360         int i, gain = AUTO_GAIN; /* tenths of a dB */
361         uint32_t dev_index = 0;
362         int device_count;
363         int ppm_error = 0;
364         char vendor[256], product[256], serial[256];
365         sem_init(&data_ready, 0, 0);
366         pyth_precompute();
367
368         while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1)
369         {
370                 switch (opt) {
371                 case 'd':
372                         dev_index = atoi(optarg);
373                         break;
374                 case 'g':
375                         gain = (int)(atof(optarg) * 10);
376                         break;
377                 case 'p':
378                         ppm_error = atoi(optarg);
379                         break;
380                 case 'V':
381                         verbose_output = 1;
382                         break;
383                 case 'S':
384                         short_output = 1;
385                         break;
386                 case 'e':
387                         allowed_errors = atoi(optarg);
388                         break;
389                 case 'Q':
390                         quality = atof(optarg);
391                         break;
392                 default:
393                         usage();
394                         return 0;
395                 }
396         }
397
398         if (argc <= optind) {
399                 filename = "-";
400         } else {
401                 filename = argv[optind];
402         }
403
404         buffer = malloc(DEFAULT_BUF_LENGTH * sizeof(uint8_t));
405
406         device_count = rtlsdr_get_device_count();
407         if (!device_count) {
408                 fprintf(stderr, "No supported devices found.\n");
409                 exit(1);
410         }
411
412         fprintf(stderr, "Found %d device(s):\n", device_count);
413         for (i = 0; i < device_count; i++) {
414                 rtlsdr_get_device_usb_strings(i, vendor, product, serial);
415                 fprintf(stderr, "  %d:  %s, %s, SN: %s\n", i, vendor, product, serial);
416         }
417         fprintf(stderr, "\n");
418
419         fprintf(stderr, "Using device %d: %s\n",
420                 dev_index, rtlsdr_get_device_name(dev_index));
421
422         r = rtlsdr_open(&dev, dev_index);
423         if (r < 0) {
424                 fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
425                 exit(1);
426         }
427 #ifndef _WIN32
428         sigact.sa_handler = sighandler;
429         sigemptyset(&sigact.sa_mask);
430         sigact.sa_flags = 0;
431         sigaction(SIGINT, &sigact, NULL);
432         sigaction(SIGTERM, &sigact, NULL);
433         sigaction(SIGQUIT, &sigact, NULL);
434         sigaction(SIGPIPE, &sigact, NULL);
435 #else
436         SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
437 #endif
438
439         if (strcmp(filename, "-") == 0) { /* Write samples to stdout */
440                 file = stdout;
441                 setvbuf(stdout, NULL, _IONBF, 0);
442 #ifdef _WIN32
443                 _setmode(_fileno(file), _O_BINARY);
444 #endif
445         } else {
446                 file = fopen(filename, "wb");
447                 if (!file) {
448                         fprintf(stderr, "Failed to open %s\n", filename);
449                         exit(1);
450                 }
451         }
452
453         /* Set the tuner gain */
454         if (gain == AUTO_GAIN) {
455                 r = rtlsdr_set_tuner_gain_mode(dev, 0);
456         } else {
457                 r = rtlsdr_set_tuner_gain_mode(dev, 1);
458                 r = rtlsdr_set_tuner_gain(dev, gain);
459         }
460         if (r != 0) {
461                 fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
462         } else if (gain == AUTO_GAIN) {
463                 fprintf(stderr, "Tuner gain set to automatic.\n");
464         } else {
465                 fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0);
466         }
467
468         r = rtlsdr_set_freq_correction(dev, ppm_error);
469         r = rtlsdr_set_agc_mode(dev, 1);
470
471         /* Set the tuner frequency */
472         r = rtlsdr_set_center_freq(dev, ADSB_FREQ);
473         if (r < 0) {
474                 fprintf(stderr, "WARNING: Failed to set center freq.\n");}
475         else {
476                 fprintf(stderr, "Tuned to %u Hz.\n", ADSB_FREQ);}
477
478         /* Set the sample rate */
479         fprintf(stderr, "Sampling at %u Hz.\n", ADSB_RATE);
480         r = rtlsdr_set_sample_rate(dev, ADSB_RATE);
481         if (r < 0) {
482                 fprintf(stderr, "WARNING: Failed to set sample rate.\n");}
483
484         /* Reset endpoint before we start reading from it (mandatory) */
485         r = rtlsdr_reset_buffer(dev);
486         if (r < 0) {
487                 fprintf(stderr, "WARNING: Failed to reset buffers.\n");}
488
489         /* flush old junk */
490         sleep(1);
491         rtlsdr_read_sync(dev, NULL, 4096, NULL);
492
493         pthread_create(&demod_thread, NULL, demod_thread_fn, (void *)(NULL));
494         rtlsdr_read_async(dev, rtlsdr_callback, (void *)(NULL),
495                               DEFAULT_ASYNC_BUF_NUMBER,
496                               DEFAULT_BUF_LENGTH);
497
498
499         if (do_exit) {
500                 fprintf(stderr, "\nUser cancel, exiting...\n");}
501         else {
502                 fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
503         rtlsdr_cancel_async(dev);
504
505         if (file != stdout) {
506                 fclose(file);}
507
508         rtlsdr_close(dev);
509         free(buffer);
510         return r >= 0 ? r : -r;
511 }
512