diff --git a/scan/reset_usb.c b/scan/reset_usb.c new file mode 100644 index 0000000..48c8aa7 --- /dev/null +++ b/scan/reset_usb.c @@ -0,0 +1,25 @@ + +/* +http://askubuntu.com/questions/645/how-do-you-reset-a-usb-device-from-the-command-line +$ lsusb +Bus 001 Device 006: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T +$ (sudo) ./reset_usb /dev/bus/usb/001/006 +*/ + +#include +#include +#include +#include + +int main(int argc, char **argv) { + const char *filename; + int fd; + + filename = argv[1]; + fd = open(filename, O_WRONLY); + ioctl(fd, USBDEVFS_RESET, 0); + close(fd); + + return 0; +} + diff --git a/scan/rs_detect.c b/scan/rs_detect.c new file mode 100644 index 0000000..cb6be23 --- /dev/null +++ b/scan/rs_detect.c @@ -0,0 +1,345 @@ + +/* + * detect/identify radiosondes + * DFM, RS92-SGP, RS41, M10, iMet-1-AB + */ + +#include +#include +#include +#include + +#ifdef CYGWIN + #include // cygwin: _setmode() + #include +#endif + + +typedef unsigned char ui8_t; +typedef unsigned int ui32_t; + +time_t rawtime; +struct tm *gmt; + + +int wavloaded = 0, + option_gmt = 0, + option_silent = 0; + + +#define DFM 2 +#define RS41 3 +#define RS92 4 +#define M10 5 +#define iMet 6 + + +#define HEADLEN 32 +#define HEADOFS 0 // HEADLEN+HEADOFS=32 + +//int dfm_baudrate = 2500; +char dfm_header[] = "01100101011001101010010110101010"; + +//int vai_baudrate = 4800; +char rs41_header[] = "00001000011011010101001110001000" + "01000100011010010100100000011111"; +char rs92_header[] = "10100110011001101001" + "10100110011001101001" + "10100110011001101001" + "10100110011001101001" + "1010011001100110100110101010100110101001"; + +//int m10_baudrate = 9600; +char m10_header[] = "00110011001100110101100110110011"; + +//int imet_baudrate = 9600; +char imet_header[] = "11110000111100001111000011110000" + "11110000""10101100110010101100101010101100" + "11110000""10101100110010101100101010101100"; + + +char buf25[HEADLEN+1] = "x"; +int bufpos25 = -1; + +char buf48[HEADLEN+1] = "x"; +int bufpos48 = -1; + +char buf96[HEADLEN+1] = "x"; +int bufpos96 = -1; + + +/* -------------------------------------------------------------------------- */ + +int sample_rate = 0, bits_sample = 0, channels = 0; + +int findstr(char *buff, char *str, int pos) { + int i; + for (i = 0; i < 4; i++) { + if (buff[(pos+i)%4] != str[i]) break; + } + return i; +} + +int read_wav_header(FILE *fp) { + char txt[4+1] = "\0\0\0\0"; + unsigned char dat[4]; + int byte, p=0; + + if (fread(txt, 1, 4, fp) < 4) return -1; + if (strncmp(txt, "RIFF", 4)) return -1; + if (fread(txt, 1, 4, fp) < 4) return -1; + // pos_WAVE = 8L + if (fread(txt, 1, 4, fp) < 4) return -1; + if (strncmp(txt, "WAVE", 4)) return -1; + // pos_fmt = 12L + for ( ; ; ) { + if ( (byte=fgetc(fp)) == EOF ) return -1; + txt[p % 4] = byte; + p++; if (p==4) p=0; + if (findstr(txt, "fmt ", p) == 4) break; + } + if (fread(dat, 1, 4, fp) < 4) return -1; + if (fread(dat, 1, 2, fp) < 2) return -1; + + if (fread(dat, 1, 2, fp) < 2) return -1; + channels = dat[0] + (dat[1] << 8); + + if (fread(dat, 1, 4, fp) < 4) return -1; + memcpy(&sample_rate, dat, 4); //sample_rate = dat[0]|(dat[1]<<8)|(dat[2]<<16)|(dat[3]<<24); + + if (fread(dat, 1, 4, fp) < 4) return -1; + if (fread(dat, 1, 2, fp) < 2) return -1; + //byte = dat[0] + (dat[1] << 8); + + if (fread(dat, 1, 2, fp) < 2) return -1; + bits_sample = dat[0] + (dat[1] << 8); + + // pos_dat = 36L + info + for ( ; ; ) { + if ( (byte=fgetc(fp)) == EOF ) return -1; + txt[p % 4] = byte; + p++; if (p==4) p=0; + if (findstr(txt, "data", p) == 4) break; + } + if (fread(dat, 1, 4, fp) < 4) return -1; + + + if (!option_silent) { + fprintf(stderr, "sample_rate: %d\n", sample_rate); + fprintf(stderr, "bits : %d\n", bits_sample); + fprintf(stderr, "channels : %d\n", channels); + } + + if ((bits_sample != 8) && (bits_sample != 16)) return -1; + + return 0; +} + + +#define EOF_INT 0x1000000 + +int read_signed_sample(FILE *fp) { // int = i32_t + int byte, i, ret; // EOF -> 0x1000000 + + for (i = 0; i < channels; i++) { + // i = 0: links bzw. mono + byte = fgetc(fp); + if (byte == EOF) return EOF_INT; + if (i == 0) ret = byte; + + if (bits_sample == 16) { + byte = fgetc(fp); + if (byte == EOF) return EOF_INT; + if (i == 0) ret += byte << 8; + } + + } + + if (bits_sample == 8) return ret-128; + if (bits_sample == 16) return (short)ret; + + return ret; +} + +int par=1, par_alt=1; +unsigned long sample_count = 0; + +int read_bits_fsk(FILE *fp, int *bit, int *len) { + int n, sample; + + n = 0; + do{ + sample = read_signed_sample(fp); + if (sample == EOF_INT) return EOF; + sample_count++; + par_alt = par; + par = (sample >= 0) ? 1 : -1; // 8bit: 0..127,128..255 (-128..-1,0..127) + n++; + } while (par*par_alt > 0); + + *len = n; + + *bit = (1+par_alt)/2; // oben 1, unten -1 + //*bit = (1-par_alt)/2;// sdr# 0 && sample_count > zeit*sample_rate) goto ende; + + } + +ende: + fclose(fp); + + if (!option_silent) { + printf("sample: %lu\n", sample_count); + if (zeit) printf("%ds = %d samples\n", zeit, zeit*sample_rate); + printf("found: "); + if (!header_found) printf("NO"); + else { + time(&rawtime); + gmt = gmtime(&rawtime); + if (header_found < 0) printf("-"); + if (header_found*header_found == DFM*DFM) printf("DFM"); + if (header_found*header_found == RS41*RS41) printf("RS41"); + if (header_found*header_found == RS92*RS92) printf("RS92"); + if (header_found*header_found == M10*M10) printf("M10"); + if (header_found*header_found == iMet*iMet) printf("iMet"); + if (option_gmt) { + printf(" (%4d-%02d-%02d %02d:%02dZ) ", gmt->tm_year+1900, gmt->tm_mon, + gmt->tm_mday, gmt->tm_hour, gmt->tm_min); + } + } + printf("\n"); + } + + return header_found; +} + diff --git a/scan/rtlsdr_scan.pl b/scan/rtlsdr_scan.pl new file mode 100755 index 0000000..5813de2 --- /dev/null +++ b/scan/rtlsdr_scan.pl @@ -0,0 +1,227 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use POSIX qw(strftime); + + +## rs_detect.c return: +## #define DFM 2 +## #define RS41 3 +## #define RS92 4 +## #define M10 5 +## #define iMet 6 + +my $log_dir = "log"; + +my $utc = strftime('%Y%m%d_%H%M%S', gmtime); +print $utc, "UTC", "\n"; + +my $powfile = sprintf "log_power\.csv"; + + +my $ppm = 54; +my $fos = 403200000 * ( 1 + $ppm/1000000 ); # 403.2MHz-Linie + +my $scan_f1 = "400.6M"; +my $scan_f2 = "405.9M"; + +my $line; +my @fields; + +my $date; +my $time; +my $f1; +my $f2; +my $f; +my $step; +my @db; + +my $i; +my $j; + +my $peak = 0; +my $peak_start; +my $peak_end = 0; + +my $freq; +my $ret; +my $inv; +my $dec; +my $wavfile; +my $filter; +my $breite = ""; +my $rs; +my $WFM; + +my $squelch; +my $snr = 6; + +my @peakarray; +my $num_peaks; + +print "[rtl_power: scan $scan_f1:$scan_f2]\n"; +system("timeout 30 rtl_power -p $ppm -f $scan_f1:$scan_f2:800 -i20 -1 $powfile 2>/dev/null"); +if ( $? == -1 ) { + print "Fehler: $!\n"; +} + + +my $fh; +open ($fh, '<', "$powfile") or die "Kann '$powfile' nicht oeffnen: $!\n"; + + +@peakarray = (); +my $num_lines = 0; + +while ($line = <$fh>) { + $num_lines += 1; + chomp $line; + @db = split(",", $line); + $date = $db[0]; + shift @db; + $time = $db[0]; + shift @db; + $f1 = $db[0]; + shift @db; + $f2 = $db[0]; + shift @db; + $step = $db[0]; + shift @db; + shift @db; + + my $sum = eval join '+', @db; + my $mean = $sum / scalar(@db); + #printf "level: %.1f\n", $mean; + $squelch = $mean + $snr; + + $peak = 0; + $peak_start = $peak_end = 0; + + for ($j = 0; $j < scalar(@db)-1; $j++) { + + if ($db[$j] > $squelch) { + if ($peak == 0) { + $peak_start = $f1 + $j*$step; + } + $peak = 1; + } + elsif ($peak > 0) { + if ($db[$j+1] <= $squelch) { + $peak_end = $f1 + ($j-1)*$step; + $peak = 0; + } + if ($peak_start < $peak_end) { + $freq = $peak_start + ($peak_end-$peak_start)/2; + if ( !($freq > $fos-1000 && $freq < $fos+1000) ) { ## 403.2MHz-Linie auslassen + push @peakarray, $freq; + } + } + } + + } +} +close $fh; + +if ($num_lines == 0) { + print "[reset dvb-t ...]\n"; + reset_dvbt(); +} +else { + $num_peaks = scalar(@peakarray); + for ($j = 0; $j < $num_peaks-1; $j++) { + if ($peakarray[$j+1]-$peakarray[$j] < 10e3) { # DFM peak-to-peak: 6kHz + push @peakarray, $peakarray[$j]+($peakarray[$j+1]-$peakarray[$j])/2; + } + elsif ($peakarray[$j+1]-$peakarray[$j] < 34e3) { # iMet peak-to-peak: 24kHz + push @peakarray, $peakarray[$j]+($peakarray[$j+1]-$peakarray[$j])/2; + } + } + + print "[rtl_fm: detect/decode]\n"; + + for ($j = 0; $j < $num_peaks; $j++) { + + $freq = sprintf "%.0f", $peakarray[$j]; + + eval { + local $SIG{ALRM} = sub {die "alarm\n"}; + alarm 30; # beide Bandbreiten + print "\n$freq Hz: "; # detect ohne highpass 20 + system("timeout 12s rtl_fm -p $ppm -M fm -s 15k -f $freq 2>/dev/null |\ + sox -t raw -r 15k -e s -b 16 -c 1 - -r 48000 -t wav - 2>/dev/null |\ + ./rs_detect -s -z -t 8 2>/dev/null"); + $ret = $? >> 8; + if (!$ret) { # mehr Bandbreite bei iMet + system("timeout 12s rtl_fm -p $ppm -M fm -s 36k -o 4 -f $freq 2>/dev/null |\ + sox -t raw -r 36k -e s -b 16 -c 1 - -r 48000 -t wav - 2>/dev/null |\ + ./rs_detect -s -z -t 8 2>/dev/null"); + $ret = $? >> 8; + } + alarm 0; + }; + if ($@) { + die unless $@ =~ /alarm/; + reset_dvbt(); + print "[reset dvb-t ...]\n"; + } + + if ($ret) { + if ($ret & 0x80) { + $inv = '-i'; + $ret = - (0x100 - $ret); # obwohl ($ret & 0x80) = core dump + } + else { $inv = ''; } + $rs = ""; + $WFM = ""; + if (abs($ret) == 2) { $rs = "dfm"; $breite = "15k"; $dec = './dfm06 -v'; $filter = "lowpass 2000 highpass 20"; } + if (abs($ret) == 3) { $rs = "rs41"; $breite = "12k"; $dec = './rs41stdin -v'; $filter = "lowpass 2600"; } + if (abs($ret) == 4) { $rs = "rs92"; $breite = "12k"; $dec = './rs92gps -g -v -a almanac.txt'; $filter = "lowpass 2500 highpass 20"; } + if (abs($ret) == 5) { $rs = "m10"; $breite = "24k"; $dec = './m10x -v'; $filter = "highpass 20"; } + if (abs($ret) == 6) { $rs = "imet"; $breite = "40k"; $dec = './imet1ab -v'; $filter = "highpass 20"; $WFM = "-o 4"; } + if ($inv) { print "-";} print uc($rs)," ($utc)\n"; + $utc = strftime('%Y%m%d_%H%M%S', gmtime); + $wavfile = $rs."-".$utc."Z-".$freq."Hz.wav"; + if ($rs) { + system("timeout 30s rtl_fm -p $ppm -M fm $WFM -s $breite -f $freq 2>/dev/null |\ + sox -t raw -r $breite -e s -b 16 -c 1 - -r 48000 -b 8 -t wav - $filter 2>/dev/null |\ + tee $log_dir/$wavfile | $dec $inv 2>/dev/null"); + } + } + + } + print "\n"; +} + +print "\n=\n"; + + +## $snr: peak sensitivity: wenn zu niedrig, viele Kandidaten; +## wenn zu hoch, zu wenige (rs41 sendet nur 1/2 sek. +## andere Methoden: +## Fenster/Bandbreite aufsummieren/integrieren; Schwerpunkt; +## rtl-sdr IQ-Band: 1 Minute aufnehmen und dann analysieren/scannen. +## +## rs92: aktuellen (SEM) almanac.txt +## wenn brdc-emphemerides (-e) benutzt werden, darauf achten, dass diese +## aktuell sind, wenn ueber laengeren Zeitraum gescannt wird +## +## rs_detect.c und decoder: gleiche Polaritaet in read_bits_fsk(), +## am besten als gemeinsame include-Datei wav_audio.c +################################################################################################### + + +## http://askubuntu.com/questions/645/how-do-you-reset-a-usb-device-from-the-command-line +## usbreset.c -> reset_usb +sub reset_dvbt { + my @devices = split("\n",`lsusb`); + foreach my $line (@devices) { + if ($line =~ /\w+\s(\d+)\s\w+\s(\d+):\sID\s([0-9a-f]+):([0-9a-f]+).+Realtek Semiconductor Corp\./) { + if ($4 eq "2832" || $4 eq "2838") { + system("./reset_usb /dev/bus/usb/$1/$2"); + } + } + } +} +