Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ in something resembling real-time.

On Ubuntu, run:
```
$ sudo python speccy.py wlan0 wlan1 ...
$ sudo python3 speccy.py wlan0 wlan1 ...
```
where ```wlanN``` are the devices you'd like to use. Up to four devices are supported.

Expand Down
29 changes: 16 additions & 13 deletions benchmark.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from spectrum_file import SpectrumFileReader
from scanner import Scanner
import sys
import Queue
from queue import Queue
from datetime import datetime, timedelta
import time

class AthBenchmark(object):

class AthBenchmark(object):
def __init__(self, iface):
self.scanner = Scanner(iface)
fn = '%s/spectral_scan0' % self.scanner.get_debugfs_dir()
fn = "%s/spectral_scan0" % self.scanner.get_debugfs_dir()
self.file_reader = SpectrumFileReader(fn)
self.interface = iface

Expand All @@ -22,36 +22,39 @@ def get_samples(self, duration):
except Queue.Empty:
continue
sps += len(samples) / (17 + 56) # (header + payload in HT20)
print "total: %d sps" % sps
print("total: %d sps" % sps)
sps /= float(duration)
return sps

# count samples in chanscan
def benchmark_chanscan(self, duration=5, samplecount=8):
print "\nrun benchmark chanscan with samplecount=%d, duration=%d " % (samplecount, duration)
print(
"\nrun benchmark chanscan with samplecount=%d, duration=%d "
% (samplecount, duration)
)
self.scanner.cmd_set_samplecount(samplecount)
self.scanner.mode_chanscan()
self.scanner.start()
sps = self.get_samples(duration=duration)
self.scanner.stop()
self.file_reader.flush()
print "%.2f sps, chanscan" % sps
print("%.2f sps, chanscan" % sps)
return sps

# count samples in bg mode (w/o) load
def benchmark_background(self, duration=5):
print "\nrun benchmark background with duration=%d " % duration
print("\nrun benchmark background with duration=%d " % duration)
self.scanner.mode_noninvasive_background()
self.scanner.dev_add_monitor()
self.scanner.start()
sps = self.get_samples(duration=duration)
self.scanner.stop()
self.file_reader.flush()
print "%.2f sps, background scan " % sps
print("%.2f sps, background scan " % sps)
return sps

def benchmark_manual(self, samplecount=127):
print "\nrun benchmark manual with samplecount=%d " % samplecount
print("\nrun benchmark manual with samplecount=%d " % samplecount)
self.scanner.mode_manual()
self.scanner.cmd_manual()
self.scanner.cmd_set_samplecount(samplecount)
Expand All @@ -68,14 +71,14 @@ def benchmark_manual(self, samplecount=127):
reread -= 1
self.scanner.stop()
self.file_reader.flush()
print "got %d samples in manual mode" % sps
print("got %d samples in manual mode" % sps)
return sps

def main(self):
samplecount = [1, 10, 50, 100, 150, 200, 255]
for sc in samplecount:
sps = self.benchmark_chanscan( duration=5, samplecount=sc)
print "sps / samplecount: %.2f" % (sps / sc)
sps = self.benchmark_chanscan(duration=5, samplecount=sc)
print("sps / samplecount: %.2f" % (sps / sc))
time.sleep(0.2)

self.benchmark_background(duration=5)
Expand All @@ -91,5 +94,5 @@ def cleanup(self):
self.file_reader.stop()


if __name__ == '__main__':
if __name__ == "__main__":
AthBenchmark(sys.argv[1]).main()
17 changes: 9 additions & 8 deletions example_offline_analysis.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from spectrum_file import SpectrumFileReader
import cPickle
import pickle
import os


def process(fn):
print "processing '%s':" % fn
f = open(fn, 'r')
print("processing '%s':" % fn)
f = open(fn, "r")
while True:
try:
device_id, ts, sample_data = cPickle.load(f)
device_id, ts, sample_data = pickle.load(f)
for tsf, freq, noise, rssi, pwrs in SpectrumFileReader.decode(sample_data):
print device_id, ts, tsf, freq, noise, rssi
print(device_id, ts, tsf, freq, noise, rssi)
for carrier_freq, pwr_level in pwrs.iteritems():
print carrier_freq, pwr_level
print(carrier_freq, pwr_level)
except EOFError:
break

Expand All @@ -21,7 +21,8 @@ def process(fn):
def main():
for fn in os.listdir("./spectral_data"):
if fn.endswith(".bin"):
process("./spectral_data/"+fn)
process("./spectral_data/" + fn)

if __name__ == '__main__':

if __name__ == "__main__":
main()
99 changes: 56 additions & 43 deletions scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ class Scanner(object):
run = True

def dev_to_phy(self, dev):
f = open('/sys/class/net/%s/phy80211/name' % dev)
f = open("/sys/class/net/%s/phy80211/name" % dev)
phy = f.read().strip()
f.close()
return phy

def freq_to_chan(self, freq):
chan = 0
if (freq >= 2412 and freq <= 2472):
if freq >= 2412 and freq <= 2472:
chan = (freq - 2407) / 5
if (freq >= 5180 and freq <= 5900):
if freq >= 5180 and freq <= 5900:
chan = (freq - 5000) / 5
return chan

def _find_debugfs_dir(self):
''' search debugfs for spectral_scan_ctl for this interface '''
for dirname, subd, files in os.walk('/sys/kernel/debug/ieee80211'):
if 'spectral_scan_ctl' in files:
"""search debugfs for spectral_scan_ctl for this interface"""
for dirname, subd, files in os.walk("/sys/kernel/debug/ieee80211"):
if "spectral_scan_ctl" in files:
phy = dirname.split(os.path.sep)[-2]
if phy == self.dev_to_phy(self.interface):
self.phy = phy
Expand All @@ -45,13 +45,13 @@ def _scan(self):
self.cmd_trigger()

if self.mode.value == 1: # only in 'chanscan' mode
cmd = 'iw dev %s scan' % self.interface
cmd = "iw dev %s scan" % self.interface
self.lock.acquire()
if self.freqlist:
cmd = '%s freq %s' % (cmd, ' '.join(self.freqlist))
cmd = "%s freq %s" % (cmd, " ".join(self.freqlist))
self.lock.release()
os.system('%s >/dev/null 2>/dev/null' % cmd)
time.sleep(.01)
os.system("%s >/dev/null 2>/dev/null" % cmd)
time.sleep(0.01)

def __init__(self, interface, idx=0):
self.interface = interface
Expand All @@ -62,16 +62,19 @@ def __init__(self, interface, idx=0):
self.monitor_added = False
self.debugfs_dir = self._find_debugfs_dir()
if not self.debugfs_dir:
raise Exception, \
'Unable to access spectral_scan_ctl file for interface %s' % interface
raise Exception(
"Unable to access spectral_scan_ctl file for interface %s" % interface
)

self.is_ath10k = self.debugfs_dir.endswith("ath10k")
self.ctl_file = '%s/spectral_scan_ctl' % self.debugfs_dir
self.sample_count_file = '%s/spectral_count' % self.debugfs_dir
self.short_repeat_file = '%s/spectral_short_repeat' % self.debugfs_dir
self.ctl_file = "%s/spectral_scan_ctl" % self.debugfs_dir
self.sample_count_file = "%s/spectral_count" % self.debugfs_dir
self.short_repeat_file = "%s/spectral_short_repeat" % self.debugfs_dir
self.cur_chan = 6
self.sample_count = 8
self.mode = Value('i', -1) # -1 = undef, 1 = 'chanscan', 2 = 'background scan', 3 = 'noninvasive bg scan'
self.mode = Value(
"i", -1
) # -1 = undef, 1 = 'chanscan', 2 = 'background scan', 3 = 'noninvasive bg scan'
self.channel_mode = "HT20"
self.thread = None
self.file_reader = None
Expand All @@ -80,14 +83,14 @@ def __init__(self, interface, idx=0):

def set_freqs(self, minf, maxf, spacing):
self.lock.acquire()
self.freqlist = ['%s' % x for x in range(minf, maxf + spacing, spacing)]
self.freqlist = ["%s" % x for x in range(minf, maxf + spacing, spacing)]
self.lock.release()
# TODO restart scanner
self.freq_idx = 0;
print "freqlist: %s" % self.freqlist
self.freq_idx = 0
print("freqlist: %s" % self.freqlist)

def hw_setup_chanscan(self):
print "enter 'chanscan' mode: set dev type to 'managed'"
print("enter 'chanscan' mode: set dev type to 'managed'")
os.system("ip link set %s down" % self.interface)
os.system("iw dev %s set type managed" % self.interface)
os.system("ip link set %s up" % self.interface)
Expand All @@ -100,7 +103,7 @@ def hw_setup_background(self):
if self.noninvasive:
self.dev_add_monitor()
else:
print "enter 'background' mode: set dev type to 'monitor'"
print("enter 'background' mode: set dev type to 'monitor'")
os.system("ip link set %s down" % self.interface)
os.system("iw dev %s set type monitor" % self.interface)
os.system("ip link set %s up" % self.interface)
Expand Down Expand Up @@ -131,7 +134,7 @@ def retune_up(self): # FIXME: not save for 5Ghz / ath10k

idx = (self.freq_idx + 1) % len(self.freqlist)

print "tune to freq %s" % self.freqlist[idx]
print("tune to freq %s" % self.freqlist[idx])
self.fix_ht40_mode()
self.cmd_setfreq(idx)
self.cmd_trigger()
Expand All @@ -142,14 +145,16 @@ def retune_down(self): # FIXME: not save for 5Ghz / ath10k

idx = (self.freq_idx - 1) % len(self.freqlist)

print "tune to freq %s" % self.freqlist[idx]
print("tune to freq %s" % self.freqlist[idx])
self.fix_ht40_mode()
self.cmd_setfreq(idx)
self.cmd_trigger()

def cmd_samplecount_up(self):
self.sample_count *= 2
if self.sample_count == 256: # special case, 256 is not valid, set to last valid value
if (
self.sample_count == 256
): # special case, 256 is not valid, set to last valid value
self.sample_count = 255
if self.sample_count > 255:
self.sample_count = 1
Expand All @@ -158,72 +163,78 @@ def cmd_samplecount_up(self):
def cmd_samplecount_down(self):
if self.sample_count == 255:
self.sample_count = 256 # undo special case, see above
self.sample_count /= 2
self.sample_count //= 2
if self.sample_count < 1:
self.sample_count = 255
self.cmd_set_samplecount(self.sample_count)

def cmd_trigger(self):
f = open(self.ctl_file, 'w')
f = open(self.ctl_file, "w")
f.write("trigger")
f.close()

def cmd_background(self):
f = open(self.ctl_file, 'w')
f = open(self.ctl_file, "w")
f.write("background")
if self.is_ath10k:
f.write("trigger")
f.close()

def cmd_manual(self):
f = open(self.ctl_file, 'w')
f = open(self.ctl_file, "w")
f.write("manual")
f.close()

def cmd_chanscan(self):
f = open(self.ctl_file, 'w')
f = open(self.ctl_file, "w")
f.write("chanscan")
f.close()

def cmd_disable(self):
f = open(self.ctl_file, 'w')
f = open(self.ctl_file, "w")
f.write("disable")
f.close()

def cmd_set_samplecount(self, count):
print "set sample count to %d" % count
f = open(self.sample_count_file, 'w')
print("set sample count to %d" % count)
f = open(self.sample_count_file, "w")
f.write("%s" % count)
f.close()

def set_short_repeat(self, short_repeat):
f = open(self.short_repeat_file, 'w')
f = open(self.short_repeat_file, "w")
f.write("%s" % short_repeat)
f.close()

def cmd_toggle_short_repeat(self):
f = open(self.short_repeat_file, 'r')
f = open(self.short_repeat_file, "r")
curval = int(f.read())
f.close()
if curval == 0:
curval = 1
else:
curval = 0
print "set short repeat to %d" % curval
print("set short repeat to %d" % curval)
self.set_short_repeat(curval)

def cmd_setchannel(self):
print "set channel to %d in mode %s" % (self.cur_chan, self.channel_mode)
print("set channel to %d in mode %s" % (self.cur_chan, self.channel_mode))
if not self.noninvasive:
os.system("iw dev %s set channel %d %s" % (self.interface, self.cur_chan, self.channel_mode))
os.system(
"iw dev %s set channel %d %s"
% (self.interface, self.cur_chan, self.channel_mode)
)
else: # this seems to be strange:
os.system("iw dev %s set channel %d %s" % (self.monitor_name, self.cur_chan, self.channel_mode))
os.system(
"iw dev %s set channel %d %s"
% (self.monitor_name, self.cur_chan, self.channel_mode)
)

def cmd_setfreq(self, idx):
freq = self.freqlist[idx]
chan = self.freq_to_chan(int(freq))
mode = self.channel_mode
print "set freq to %s (%d) in mode %s" % (freq, chan, mode)
print("set freq to %s (%d) in mode %s" % (freq, chan, mode))
if not self.noninvasive:
os.system("iw dev %s set freq %s %s" % (self.interface, freq, mode))
else: # this seems to be strange:
Expand All @@ -240,8 +251,8 @@ def fix_ht40_mode(self):

def cmd_toggle_HTMode(self):
if self.channel_mode == "HT40+" or self.channel_mode == "HT40-":
self.channel_mode = "HT20"
else: # see https://wireless.wiki.kernel.org/en/developers/regulatory/processing_rules#mhz_channels1
self.channel_mode = "HT20"
else: # see https://wireless.wiki.kernel.org/en/developers/regulatory/processing_rules#mhz_channels1
if self.cur_chan < 8:
self.channel_mode = "HT40+"
else:
Expand All @@ -252,8 +263,10 @@ def cmd_toggle_HTMode(self):
def dev_add_monitor(self):
if self.monitor_added:
return
print "add a monitor interface"
os.system("iw phy %s interface add %s type monitor" % (self.phy, self.monitor_name))
print("add a monitor interface")
os.system(
"iw phy %s interface add %s type monitor" % (self.phy, self.monitor_name)
)
os.system("ip link set %s up" % self.monitor_name)
self.monitor_added = True

Expand Down
Loading