1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This is the main program that
# - Runs rtlsdr and etisnoop for 200 ETI frames
# and generate the stats.yml
# - Runs a webserver
#
# Copyright (C) 2017
# Matthias P. Braendli, matthias.braendli@mpb.li
# http://www.opendigitalradio.org
# Licence: The MIT License, see LICENCE file
import sys
from bottle import route, run, template, static_file, request
import subprocess
import time
import datetime
import multiprocessing as mp
import threading
import shlex
import argparse
import collections
class StatCollector(threading.Thread):
def __init__(self, options):
threading.Thread.__init__(self)
self.num_eti_frames = int(options.num_eti_frames)
self.gain = int(options.gain)
self.freq = int(options.freq)
self.event_stop = threading.Event()
self.dab2eti_proc = None
self.stats_lock = threading.Lock()
self.stats = None
def run(self):
if self.gain == 0:
gain = ""
else:
gain = self.gain
dab2eti_cmdline = "dab2eti {} {} | etisnoop -s stats.yml -n {}".format(
self.freq, gain, self.num_eti_frames)
print("Cmdline: " + repr(dab2eti_cmdline))
while not self.event_stop.is_set():
print("Entering capture loop, start RX")
self.dab2eti_proc = subprocess.Popen(dab2eti_cmdline, shell=True)
ret = self.dab2eti_proc.wait()
print("Quit with return value {}".format(ret))
self.stats_lock.acquire()
try:
self.stats = open("stats.yml").read()
print("Stats loaded, {} chars".format(len(self.stats)))
except Exception as e:
self.stats = "exception: {}".format(e)
finally:
self.stats_lock.release()
time.sleep(15)
def stop(self):
print("Set stop event")
self.event_stop.set()
self.join()
def getstats(self):
"""Return a str YAML if stats are available, or None"""
self.stats_lock.acquire()
stats = self.stats
self.stats_lock.release()
return stats
@route('/')
def index():
stats = stat_collector.getstats()
if stats is None:
stats = "status: not ready"
return template('index',
freq = cli_args.freq,
gain = cli_args.gain,
stats = stats)
@route('/static/<filename:path>')
def send_static(filename):
return static_file(filename, root='./static')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='ETISnoop statistics')
# Options for the webserver
parser.add_argument('--host', default='127.0.0.1', help='socket host (default: 127.0.0.1)',required=False)
parser.add_argument('--port', default='8000', help='socket port (default: 8000)',required=False)
# Options for RTLSDR reception
parser.add_argument('--freq', help='Receive frequency', required=True)
parser.add_argument('--num-eti-frames',
default=200,
help='Number of ETI frames to analyse.',
required=False)
parser.add_argument('--gain', default=0,
help='Gain setting for rtl_sdr, 0 for auto', required=False)
cli_args = parser.parse_args()
stat_collector = StatCollector(cli_args)
stat_collector.start()
try:
run(host=cli_args.host, port=int(cli_args.port), debug=True, reloader=False)
finally:
stat_collector.stop()
|