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
27 changes: 17 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#
# gr-scan - A GNU Radio signal scanner
# Copyright (C) 2015 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
# Copyright (C) 2012 Nicholas Tomlinson
#
# This program is free software: you can redistribute it and/or modify
Expand All @@ -16,17 +17,23 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

VERSION=2013102901
CXXFLAGS=-DVERSION="\"gr-scan $(VERSION)\"" -Wall -lgnuradio-filter -lgnuradio-blocks -lgnuradio-pmt -lgnuradio-fft -lgnuradio-runtime -lgnuradio-osmosdr -lboost_system -O2 -s -Wno-unused-function
VERSION = 20160104
CXXFLAGS ?= -O3 -march=native -fomit-frame-pointer
CXXFLAGS +=-DVERSION="\"gr-scan $(VERSION)\"" -Wall
LDLIBS = -lgnuradio-filter -lgnuradio-blocks -lgnuradio-pmt -lgnuradio-fft -lgnuradio-runtime -lgnuradio-osmosdr -lboost_system -lfmt

gr-scan: *.cpp *.hpp Makefile
g++ $(CXXFLAGS) -o gr-scan main.cpp
PREFIX ?= /usr
DESTDIR ?=
BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
MANDIR ?= $(PREFIX)/share/man

all: gr-scan

gr-scan: *.cpp *.hpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) *.cpp -o gr-scan $(LDLIBS) $(LDFLAGS)
clean:
rm -f gr-scan gr-scan.tar.gz
rm -f gr-scan

dist:
mkdir gr-scan-$(VERSION)
cp *.cpp *.hpp Makefile COPYING gr-scan-$(VERSION)
tar -cf - gr-scan-$(VERSION) | gzip -9 -c - > gr-scan-$(VERSION).tar.gz
rm -r gr-scan-$(VERSION)
install: gr-scan
@install -v -d "$(DESTDIR)$(BINDIR)" && install -s -m 0755 -v gr-scan "$(DESTDIR)$(BINDIR)/gr-scan"
4 changes: 4 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ Fast radio spectrum scanner based on SDR and GnuRadio.

Tune to frequencies in specified range and tri fing peak in frequency power spectrum.
Print frequency and bandwidth of found peaks.

Example Useage:
./gr-scan -x 17 -y 20 -d rtl=0
./gr-scan -x 100 -y 103 -d file=./out.wav,rate=2000000
27 changes: 25 additions & 2 deletions arguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <stdlib.h>
#include <argp.h>
#include <string>

class Arguments
{
Expand All @@ -33,7 +34,8 @@ class Arguments
sample_rate(2000000.0),
fft_width(1000.0),
step(-1.0),
ptime(-1.0)
ptime(-1.0),
device()
{
argp_parse (&argp_i, argc, argv, 0, 0, this);
}
Expand Down Expand Up @@ -103,6 +105,17 @@ class Arguments
return ptime;
}

std::string get_outcsv()
{
return outcsv;
}


char *get_device()
{
return &*device.begin();
}

private:
static error_t s_parse_opt(int key, char *arg, struct argp_state *state)
{
Expand Down Expand Up @@ -147,6 +160,12 @@ class Arguments
case 'p':
ptime = atof(arg);
break;
case 'o':
outcsv = std::string(arg);
break;
case 'd':
device = std::string(arg);
break;
case ARGP_KEY_ARG:
if (state->arg_num > 0){
argp_usage (state);
Expand Down Expand Up @@ -177,6 +196,8 @@ class Arguments
double fft_width;
double step;
double ptime;
std::string outcsv;
std::string device;
};

argp_option Arguments::options[] = {
Expand All @@ -191,6 +212,8 @@ argp_option Arguments::options[] = {
{"fft-width", 'w', "COUNT", 0, "Width of FFT in samples"},
{"step", 'z', "FREQ", 0, "Increment step in MHz"},
{"time", 'p', "TIME", 0, "Time in seconds to scan on each frequency"},
{"output-csv", 'o', "OUTCSV", 0, "Output results to CSV file (default: [none])"},
{"device", 'd', "DEVICE", 0, "Specify device to use. Ex. rtl=0 or hackrf=1 (Mandatory)"},
{0}
};
argp Arguments::argp_i = {options, s_parse_opt, 0, 0};
Expand All @@ -211,4 +234,4 @@ const char *argp_program_version =
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program. If not, see <http://www.gnu.org/licenses/>.";
"along with this program. If not, see <http://www.gnu.org/licenses/>.";
5 changes: 4 additions & 1 deletion main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// Modified to include https://git.zx2c4.com/gr-scan/tree/main.cpp

#include <cstdio>

Expand All @@ -37,7 +38,9 @@ int main(int argc, char **argv)
arguments.get_avg_size(),
arguments.get_spread(),
arguments.get_threshold(),
arguments.get_time());
arguments.get_time(),
arguments.get_outcsv(),
arguments.get_device());
top_block.run();
return 0; //actually, we never get here because of the rude way in which we end the scan
}
53 changes: 47 additions & 6 deletions scanner_sink.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// Modified to output CSV from https://git.zx2c4.com/gr-scan/tree/scanner_sink.hpp

#include <ctime>
#include <set>
#include <utility>
#include <string>

#include <boost/shared_ptr.hpp>

Expand All @@ -31,7 +34,8 @@ class scanner_sink : public gr::block
{
public:
scanner_sink(osmosdr::source::sptr source, unsigned int vector_length, double centre_freq_1, double centre_freq_2, double bandwidth0, double bandwidth1, double bandwidth2,
double step, unsigned int avg_size, double spread, double threshold, double ptime) :
double step, unsigned int avg_size, double spread, double threshold, double ptime,
const std::string &outcsv) :
gr::block ("scanner_sink",
gr::io_signature::make (1, 1, sizeof (float) * vector_length),
gr::io_signature::make (0, 0, 0)),
Expand All @@ -50,14 +54,31 @@ class scanner_sink : public gr::block
m_threshold(threshold), //threshold in dB for discovery
m_spread(spread), //minumum distance between radio signals (overlapping scans might produce slightly different frequencies)
m_time(ptime), //the amount of time to listen on the same frequency for
m_start_time(time(0)) //the start time of the scan (useful for logging/reporting/monitoring)
m_start_time(time(0)), //the start time of the scan (useful for logging/reporting/monitoring)
m_outcsv(NULL)
{
ZeroBuffer();
//Taken from https://git.zx2c4.com/gr-scan/tree/scanner_sink.hpp
if (!outcsv.empty()) {
bool write_csv_header = access(outcsv.c_str(), F_OK) == -1;
m_outcsv = fopen(outcsv.c_str(), "a+");
if (!m_outcsv) {
fprintf(stderr, "[-] Error opening output CSV file %s\n", outcsv.c_str());
exit(1);
}
if (write_csv_header) {
fprintf(m_outcsv, "time,frequency_mhz,width_khz,peak,diff\n");
fflush(m_outcsv);
}
}
}

virtual ~scanner_sink()
{
delete []m_buffer; //delete the buffer
//Taken from https://git.zx2c4.com/gr-scan/tree/scanner_sink.hpp
if (m_outcsv)
fclose(m_outcsv);
}

private:
Expand Down Expand Up @@ -159,6 +180,8 @@ class scanner_sink : public gr::block
if (TrySignal(freqs[max], freqs[min])){
printf("[+] %02u:%02u:%02u: Found signal: at %f MHz of width %f kHz, peak power %f dB (difference %f dB)\n",
hours, minutes, seconds, (freqs[max] + freqs[min]) / 2000000.0, (freqs[max] - freqs[min])/1000.0, bands1[peak], diffs[peak]);
// Taken from https://git.zx2c4.com/gr-scan/tree/scanner_sink.hpp
WriteCSV((freqs[max] + freqs[min]) / 2000000.0, (freqs[max] - freqs[min])/1000.0, bands1[peak], diffs[peak]);
}
}
}
Expand All @@ -182,7 +205,7 @@ class scanner_sink : public gr::block
}

/* check to see if the signal is close to any other (the same signal often appears with a slightly different centre frequency) */
BOOST_FOREACH (double signal, m_signals){
for (double signal : m_signals){
if ((mid - signal < m_spread) && (signal - mid < m_spread)){ //tpo close
return false; //if so, this is not a genuine hit
}
Expand Down Expand Up @@ -235,6 +258,23 @@ class scanner_sink : public gr::block
}
}

// Taken from https://git.zx2c4.com/gr-scan/tree/scanner_sink.hpp
void WriteCSV(float freq, float width, float peak, float diff)
{
time_t timer;
struct tm *tm_info;
char buf[26];

if (!m_outcsv)
return;

time(&timer);
tm_info = localtime(&timer);
strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", tm_info);
fprintf(m_outcsv, "%s,%f,%f,%f,%f\n", buf, freq, width, peak, diff);
fflush(m_outcsv);
}

//std::set<std::pair<double, double>> m_signals;
std::set<double> m_signals;
osmosdr::source::sptr m_source;
Expand All @@ -253,12 +293,13 @@ class scanner_sink : public gr::block
double m_spread;
double m_time;
time_t m_start_time;
FILE *m_outcsv;
};

/* Shared pointer thing gnuradio is fond of */
typedef boost::shared_ptr<scanner_sink> scanner_sink_sptr;
typedef std::shared_ptr<scanner_sink> scanner_sink_sptr;
scanner_sink_sptr make_scanner_sink(osmosdr::source::sptr source, unsigned int vector_length, double centre_freq_1, double centre_freq_2, double bandwidth0, double bandwidth1, double bandwidth2,
double step, unsigned int avg_size, double spread, double threshold, double ptime)
double step, unsigned int avg_size, double spread, double threshold, double ptime, const std::string &outcsv)
{
return boost::shared_ptr<scanner_sink>(new scanner_sink(source, vector_length, centre_freq_1, centre_freq_2, bandwidth0, bandwidth1, bandwidth2, step, avg_size, spread, threshold, ptime));
return std::shared_ptr<scanner_sink>(new scanner_sink(source, vector_length, centre_freq_1, centre_freq_2, bandwidth0, bandwidth1, bandwidth2, step, avg_size, spread, threshold, ptime, outcsv));
}
30 changes: 20 additions & 10 deletions topblock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,38 @@

#include <cmath>
#include <stdint.h>
#include <string>

#include <gnuradio/top_block.h>
#include <osmosdr/source.h>
#include <gnuradio/blocks/stream_to_vector.h>
#include <gnuradio/fft/fft_vcc.h>
#include <gnuradio/fft/fft_v.h>
#include <gnuradio/blocks/complex_to_mag_squared.h>
#include <gnuradio/filter/single_pole_iir_filter_ff.h>
#include <gnuradio/blocks/nlog10_ff.h>
#include "scanner_sink.hpp"

//Modified to include https://git.zx2c4.com/gr-scan/tree/topblock.hpp

class TopBlock : public gr::top_block
{
public:
TopBlock(double centre_freq_1, double centre_freq_2, double sample_rate, double fft_width, double bandwidth1, double bandwidth2,
double step, unsigned int avg_size, double spread, double threshold, double ptime) : gr::top_block("Top Block"),
vector_length(sample_rate/fft_width),
double step, unsigned int avg_size, double spread, double threshold, double ptime, const std::string &outcsv, char *device) : gr::top_block("Top Block"),
vector_length( (sample_rate / fft_width) ),
window(GetWindow(vector_length)),

source(osmosdr::source::make()), /* OsmoSDR Source */
stv(gr::blocks::stream_to_vector::make(sizeof(float)*2, vector_length)), /* Stream to vector */
/* Based on the logpwrfft (a block implemented in python) */
fft(gr::fft::fft_vcc::make(vector_length, true, window, false, 1)),
source(osmosdr::source::make(device)), /* OsmoSDR Source if device is null then it should auto pick the lowest index device*/
stv(gr::blocks::stream_to_vector::make(sizeof(float)*2, vector_length / 2)), /* Stream to vector */

// fft_size = vector_length
fft(gr::fft::fft_v<float, false>::make(vector_length, window, false, 1)),

ctf(gr::blocks::complex_to_mag_squared::make(vector_length)),
iir(gr::filter::single_pole_iir_filter_ff::make(1.0, vector_length)),
lg(gr::blocks::nlog10_ff::make(10, vector_length, -20 * std::log10(float(vector_length)) -10 * std::log10(float(GetWindowPower()/vector_length)))),
/* Sink - this does most of the interesting work */
sink(make_scanner_sink(source, vector_length, centre_freq_1, centre_freq_2, sample_rate, bandwidth1, bandwidth2, step, avg_size, spread, threshold, ptime))
sink(make_scanner_sink(source, vector_length, centre_freq_1, centre_freq_2, sample_rate, bandwidth1, bandwidth2, step, avg_size, spread, threshold, ptime, outcsv))
{
/* Set up the OsmoSDR Source */
source->set_sample_rate(sample_rate);
Expand All @@ -62,6 +67,8 @@ class TopBlock : public gr::top_block
connect(ctf, 0, iir, 0);
connect(iir, 0, lg, 0);
connect(lg, 0, sink, 0);
// no known conversion for argument 3 from ‘scanner_sink_sptr’ {aka ‘boost::shared_ptr<scanner_sink>’} to ‘gr::basic_block_sptr’ {aka ‘std::shared_ptr<gr::basic_block>’}

}

private:
Expand All @@ -85,7 +92,7 @@ class TopBlock : public gr::top_block
double GetWindowPower()
{
double total = 0.0;
BOOST_FOREACH (double d, window){
for (double d : window){
total += d*d;
}
return total;
Expand All @@ -96,7 +103,10 @@ class TopBlock : public gr::top_block

osmosdr::source::sptr source;
gr::blocks::stream_to_vector::sptr stv;
gr::fft::fft_vcc::sptr fft;

//template <class T, bool forward>
gr::fft::fft_v<float, false>::sptr fft;

gr::blocks::complex_to_mag_squared::sptr ctf;
gr::filter::single_pole_iir_filter_ff::sptr iir;
gr::blocks::nlog10_ff::sptr lg;
Expand Down