Commit 5fc88978 authored by Jenda's avatar Jenda

scanner: now implements everything from specification

parent 38ce60dd
......@@ -19,9 +19,13 @@ from libutil import Struct, safe_cast
from gnuradio.filter import firdes
def channelhelper():
ChannelHelperT = Struct("channelhelper", "rotator decim rate file taps carry rotpos firpos cylen fd_r")
ChannelHelperT = Struct("channelhelper", "")
return ChannelHelperT()
def peak(freq, bw, pipe, archive):
PeakT = Struct("peak", "freq bw pipe archive")
return PeakT(freq, bw, pipe, archive)
COMPLEX64 = 8
class KukurukuScanner():
......@@ -86,9 +90,9 @@ class KukurukuScanner():
self.sdrflush()
peaks = []
for channel in cronframe.channels:
peaks.append([channel.freq-cronframe.freq, channel.bw, channel])
peaks.append(peak(channel.freq-cronframe.freq, channel.bw, channel.pipe, True))
self.do_record(peaks, 1, None, cronframe)
self.do_record(peaks, None, cronframe)
def scan(self, scanframe):
''' Find peaks in spectrum, record if specified in allow/blacklist '''
......@@ -123,44 +127,48 @@ class KukurukuScanner():
self.dump_spectrum(acc, self.getfn(scanframe.freq, None)+".spectrum.txt")
# determine whether we stumbled upon any specified channel which has PIPE set
peaks2 = []
for peak in peaks:
modified = False
for channel in scanframe.channels:
if channel.freq - scanframe.freq - channel.bw/2 < peak[0] and \
channel.freq - scanframe.freq + channel.bw/2 > peak[0]:
if channel.freq - scanframe.freq - channel.bw/2 < peak.freq and \
channel.freq - scanframe.freq + channel.bw/2 > peak.freq:
if channel.pipe:
peaks2.append([channel.freq - scanframe.freq, channel.bw, channel.pipe])
else:
peaks2.append([channel.freq - scanframe.freq, channel.bw])
modified = True
peak.freq = channel.freq - scanframe.freq
peak.bw = channel.bw
peak.pipe = channel.pipe
peak.archive = True
if not modified:
peaks2.append(peak)
self.do_record(peaks, sbuf, scanframe)
self.do_record(peaks2, self.conf.filtermargin, sbuf, scanframe)
def find_in_interval_list(self, l, key):
def filter_blacklist(self, peaks, center):
ret = []
if not self.conf.blacklist:
return peaks
if not l:
return False
for peak in peaks:
f = peak[0]+center
pos = bisect.bisect(l, (key, None))
if pos >= len(l):
pos -= 1
pos = bisect.bisect(self.conf.blacklist, (f, None))
entry = l[pos]
if pos >= len(self.conf.blacklist):
pos -= 1
if key > entry[0] and key < entry[1]: # found
return True
entry = self.conf.blacklist[pos]
return False
def filter_blacklist(self, peaks, center):
ret = []
for peak in peaks:
f = peak.freq+center
if f < entry[0] or f > entry[1]:
if not self.find_in_interval_list(self.conf.blacklist, f):
if self.find_in_interval_list(self.conf.archivelist, f):
peak.archive = True
ret.append(peak)
continue
self.l.l("Removing blacklisted signal %i"%(peak[0]+center), "INFO")
self.l.l("Removing blacklisted signal %i"%(peak.freq+center), "INFO")
return ret
......@@ -176,7 +184,7 @@ class KukurukuScanner():
frame.gain += diff
frame.gain = np.clip(frame.gain, self.conf.mingain, self.conf.maxgain)
def do_record(self, peaks, safetymargin, buf, frame):
def do_record(self, peaks, buf, frame):
lastact = time.time()
center = frame.freq
......@@ -187,27 +195,30 @@ class KukurukuScanner():
for peak in peaks:
ch = channelhelper()
f = peak[0]
w = peak[1]*safetymargin
f = peak.freq
w = peak.bw
ch.decim = math.ceil(self.conf.rate/w)
ch.rate = self.conf.rate/ch.decim
ch.rotator = -float(f)/self.conf.rate * 2*math.pi
ch.rotpos = np.zeros(2, dtype=np.float32)
ch.rotpos[0] = 1 # start with unit vector
taps = firdes.low_pass(1, self.conf.rate, w/2, w*self.conf.transition, firdes.WIN_HAMMING)
transition_band = w*self.conf.transition
taps = firdes.low_pass(1, self.conf.rate, w/2-transition_band, transition_band, firdes.WIN_HAMMING)
ch.taps = struct.pack("=%if"%len(taps), *taps)
ch.firpos = np.zeros(1, dtype=np.int32)
ch.cylen = len(ch.taps)
ch.carry = '\0' * ch.cylen
basename = self.getfn(f+center, ch.rate)
if len(peak) >= 3 and peak[2] is not None:
if peak.pipe is not None:
(ch.fd_r, ch.file) = os.pipe()
cmdline = peak[2].replace("_FILENAME_", basename)
cmdline = peak.pipe.replace("_FILENAME_", basename)
subprocess.Popen([cmdline], shell=True, stdin=ch.fd_r, bufsize=-1)
self.l.l("Recording \"%s\" (PIPE), firlen %i"%(cmdline, len(taps)), "INFO")
else:
if peak.archive:
basename = "archive/"+basename
fullfile = basename + ".cfile"
ch.file = os.open(fullfile, os.O_WRONLY|os.O_CREAT)
ch.fd_r = None
......@@ -226,7 +237,7 @@ class KukurukuScanner():
for peak in peaks:
if self.check_activity(acc, peak, floor):
lastact = time.time()
self.l.l("%f has activity, continuing"%peak[0], "INFO")
self.l.l("%f has activity, continuing"%peak.freq, "INFO")
# xlate each channel
for ch in helpers:
......@@ -256,8 +267,8 @@ class KukurukuScanner():
binhz = self.conf.rate/self.conf.fftw
startbin = int(peak[0]/binhz - peak[1]/(2*binhz)) + self.conf.fftw/2
stopbin = int(peak[0]/binhz + peak[1]/(2*binhz)) + self.conf.fftw/2
startbin = int(peak.freq/binhz - peak.bw/(2*binhz)) + self.conf.fftw/2
stopbin = int(peak.freq/binhz + peak.bw/(2*binhz)) + self.conf.fftw/2
print(acc)
......@@ -326,8 +337,8 @@ class KukurukuScanner():
if acc[i] < floor and acc[i-1] > floor:
if (i-first) >= minspan and (i-first) <= maxspan:
f = binhz*(((i+first)/2)-self.conf.fftw/2)
w = binhz*(i-first)
peaks.append([f, w])
w = binhz*(i-first)*self.conf.filtermargin
peaks.append(peak(f, w, None, False))
self.l.l("signal at %f width %f"%(f, w), "INFO")
return peaks
......
......@@ -71,7 +71,7 @@ for opt, arg in opts:
if opt == "-d":
device = arg
elif opt == "-p":
ppm = arg
ppm = int(arg)
else:
usage()
assert False
......
......@@ -13,6 +13,9 @@ from ConfReader import ConfReader, read_modes
conf = ConfReader(os.getenv('HOME') + '/.kukuruku/gui')
modes = read_modes(os.getenv('HOME') + '/.kukuruku/modes')
blacklistfile = os.path.join(os.path.expanduser('~'), ".kukuruku/scanner/")
blacklistfile = os.path.join(blacklistfile, "blacklist.conf")
archdir = "archive"
if not os.path.isdir(archdir):
......@@ -46,7 +49,7 @@ for filename in filenames:
print("d_) delete")
print("a_) archive")
print("_n) ignore once")
print("_s) ignore by sorter")
print("_s) ignore by sorter (directly archive)")
print("_h) ignore by scanner")
print("q) just quit")
c = raw_input('Choice: __ [optional comment] ')
......@@ -76,11 +79,11 @@ for filename in filenames:
os.rename(filename, archdir + "/" + filename)
if c[1] == "s":
bl = open("blacklist.txt", "a")
bl = open(blacklistfile, "a")
bl.write("s %i %i %s\n"%(freq, rate, c[3:]))
bl.close()
elif c[1] == "h":
bl = open("blacklist.txt", "a")
bl = open(blacklistfile, "a")
bl.write("h %i %i %s\n"%(freq, rate, c[3:]))
bl.close()
......
......@@ -150,31 +150,41 @@ class ConfReader():
self.scanframes.append(frm)
# read blacklist
bl = []
# read blacklist and archivelist
blpath = os.path.join(confdir, "blacklist.conf")
if os.path.isfile(blpath):
f = open(blpath)
self.blacklist = self.read_sorted_list("h", blpath)
self.archivelist = self.read_sorted_list("i", blpath)
def read_sorted_list(self, tag, filename):
# read blacklist
l = []
if os.path.isfile(filename):
f = open(filename)
lines = f.readlines()
for line in lines:
pieces = line.strip().split(" ")
if len(pieces) >= 3:
if pieces[0] == "h":
if pieces[0] == tag:
freq = int(pieces[1])
bw = int(pieces[2])/2
bl.append((freq-bw, freq+bw))
self.blacklist = []
if len(bl) > 0:
# sort and union intervals
bl.sort(key=lambda x: x[0])
self.blacklist.append(bl[0])
for interval in bl[1:]:
if self.blacklist[-1][1] < interval[0]:
self.blacklist.append(interval)
elif self.blacklist[-1][1] == interval[0]:
self.blacklist[-1][1] = interval[1]
l.append((freq-bw, freq+bw))
if not l:
return []
unioned = []
# sort and union intervals
l.sort(key=lambda x: x[0])
unioned.append(l[0])
for interval in l[1:]:
if unioned[-1][1] < interval[0]:
unioned.append(interval)
elif unioned[-1][1] == interval[0]:
unioned[-1][1] = interval[1]
return unioned
def channel_list_from_config(self, rc):
channels = []
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment