Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- git clone git://github.com/bistromath/gr-smartnet.git
- cd gr-smartnet
- git reset --hard b3335c1441ba5d2e9266e39f7c85faf65d546ba8
- git apply <<"END_PATCH"
- diff --git a/Makefile.common b/Makefile.common
- index 4b80811..299d1a9 100644
- --- a/Makefile.common
- +++ b/Makefile.common
- @@ -35,7 +35,8 @@ AM_CPPFLAGS = \
- STD_DEFINES_AND_INCLUDES = \
- $(DEFINES) \
- -I$(GNURADIO_CORE_INCLUDEDIR) \
- - -I$(GNURADIO_CORE_INCLUDEDIR)/swig
- + -I$(GNURADIO_CORE_INCLUDEDIR)/swig \
- + -I$(GNURADIO_CORE_INCLUDEDIR)/../gruel/swig
- # includes
- grincludedir = $(includedir)/gnuradio
- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
- index 702a898..1e9dc21 100644
- --- a/src/lib/Makefile.am
- +++ b/src/lib/Makefile.am
- @@ -31,7 +31,8 @@ grinclude_HEADERS = \
- smartnet_parse.h \
- smartnet_types.h \
- smartnet_subchannel_framer.h \
- - smartnet_wavsink.h
- + smartnet_wavsink.h \
- + smartnet_wavfile.h
- ###################################
- # SWIG Python interface and library
- @@ -59,6 +60,7 @@ smartnet_la_swig_sources = \
- smartnet_packetize.cc \
- smartnet_parse.cc \
- smartnet_subchannel_framer.cc \
- + smartnet_wavfile.cc \
- smartnet_wavsink.cc
- # additional arguments to the SWIG command
- diff --git a/src/lib/smartnet_wavfile.cc b/src/lib/smartnet_wavfile.cc
- new file mode 100644
- index 0000000..a782390
- --- /dev/null
- +++ b/src/lib/smartnet_wavfile.cc
- @@ -0,0 +1,313 @@
- +/* -*- c++ -*- */
- +/*
- + * Copyright 2004,2008 Free Software Foundation, Inc.
- + *
- + * This file is part of GNU Radio
- + *
- + * GNU Radio is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 3, or (at your option)
- + * any later version.
- + *
- + * GNU Radio is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with GNU Radio; see the file COPYING. If not, write to
- + * the Free Software Foundation, Inc., 51 Franklin Street,
- + * Boston, MA 02110-1301, USA.
- + */
- +
- +#ifdef HAVE_CONFIG_H
- +#include "config.h"
- +#endif
- +
- +#include <smartnet_wavfile.h>
- +#include <cstring>
- +#include <stdint.h>
- +
- +# define VALID_COMPRESSION_TYPE 0x0001
- +
- +// WAV files are always little-endian, so we need some byte switching macros
- +
- +// FIXME: Use libgruel versions
- +
- +#ifdef WORDS_BIGENDIAN
- +
- +#ifdef HAVE_BYTESWAP_H
- +#include <byteswap.h>
- +#else
- +#warning Using non-portable code (likely wrong other than ILP32).
- +
- +static inline short int
- +bswap_16 (unsigned short int x)
- +{
- + return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
- +}
- +
- +static inline unsigned int
- +bswap_32 (unsigned int x)
- +{
- + return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
- + | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
- +}
- +#endif // HAVE_BYTESWAP_H
- +
- +static inline uint32_t
- +host_to_wav(uint32_t x)
- +{
- + return bswap_32(x);
- +}
- +
- +static inline uint16_t
- +host_to_wav(uint16_t x)
- +{
- + return bswap_16(x);
- +}
- +
- +static inline int16_t
- +host_to_wav(int16_t x)
- +{
- + return bswap_16(x);
- +}
- +
- +static inline uint32_t
- +wav_to_host(uint32_t x)
- +{
- + return bswap_32(x);
- +}
- +
- +static inline uint16_t
- +wav_to_host(uint16_t x)
- +{
- + return bswap_16(x);
- +}
- +
- +static inline int16_t
- +wav_to_host(int16_t x)
- +{
- + return bswap_16(x);
- +}
- +
- +#else
- +
- +static inline uint32_t
- +host_to_wav(uint32_t x)
- +{
- + return x;
- +}
- +
- +static inline uint16_t
- +host_to_wav(uint16_t x)
- +{
- + return x;
- +}
- +
- +static inline int16_t
- +host_to_wav(int16_t x)
- +{
- + return x;
- +}
- +
- +static inline uint32_t
- +wav_to_host(uint32_t x)
- +{
- + return x;
- +}
- +
- +static inline uint16_t
- +wav_to_host(uint16_t x)
- +{
- + return x;
- +}
- +
- +static inline int16_t
- +wav_to_host(int16_t x)
- +{
- + return x;
- +}
- +
- +#endif // WORDS_BIGENDIAN
- +
- +
- +bool
- +smartnet_wavheader_parse(FILE *fp,
- + unsigned int &sample_rate_o,
- + int &nchans_o,
- + int &bytes_per_sample_o,
- + int &first_sample_pos_o,
- + unsigned int &samples_per_chan_o)
- +{
- + // _o variables take return values
- + char str_buf[8] = {0};
- +
- + uint32_t file_size;
- + uint32_t fmt_hdr_skip;
- + uint16_t compression_type;
- + uint16_t nchans;
- + uint32_t sample_rate;
- + uint32_t avg_bytes_per_sec;
- + uint16_t block_align;
- + uint16_t bits_per_sample;
- + uint32_t chunk_size;
- +
- + size_t fresult;
- +
- + fresult = fread(str_buf, 1, 4, fp);
- + if (fresult != 4 || strncmp(str_buf, "RIFF", 4) || feof(fp)) {
- + return false;
- + }
- +
- + fresult = fread(&file_size, 1, 4, fp);
- +
- + fresult = fread(str_buf, 1, 8, fp);
- + if (fresult != 8 || strncmp(str_buf, "WAVEfmt ", 8) || feof(fp)) {
- + return false;
- + }
- +
- + fresult = fread(&fmt_hdr_skip, 1, 4, fp);
- +
- + fresult = fread(&compression_type, 1, 2, fp);
- + if (wav_to_host(compression_type) != VALID_COMPRESSION_TYPE) {
- + return false;
- + }
- +
- + fresult = fread(&nchans, 1, 2, fp);
- + fresult = fread(&sample_rate, 1, 4, fp);
- + fresult = fread(&avg_bytes_per_sec, 1, 4, fp);
- + fresult = fread(&block_align, 1, 2, fp);
- + fresult = fread(&bits_per_sample, 1, 2, fp);
- +
- + if (ferror(fp)) {
- + return false;
- + }
- +
- + fmt_hdr_skip = wav_to_host(fmt_hdr_skip);
- + nchans = wav_to_host(nchans);
- + sample_rate = wav_to_host(sample_rate);
- + bits_per_sample = wav_to_host(bits_per_sample);
- +
- + if (bits_per_sample != 8 && bits_per_sample != 16) {
- + return false;
- + }
- +
- + fmt_hdr_skip -= 16;
- + if (fmt_hdr_skip) {
- + fseek(fp, fmt_hdr_skip, SEEK_CUR);
- + }
- +
- + // data chunk
- + fresult = fread(str_buf, 1, 4, fp);
- + if (strncmp(str_buf, "data", 4)) {
- + return false;
- + }
- +
- + fresult = fread(&chunk_size, 1, 4, fp);
- + if (ferror(fp)) {
- + return false;
- + }
- +
- + // More byte swapping
- + chunk_size = wav_to_host(chunk_size);
- +
- + // Output values
- + sample_rate_o = (unsigned) sample_rate;
- + nchans_o = (int) nchans;
- + bytes_per_sample_o = (int) (bits_per_sample / 8);
- + first_sample_pos_o = (int) ftell(fp);
- + samples_per_chan_o = (unsigned) (chunk_size / (bytes_per_sample_o * nchans));
- + return true;
- +}
- +
- +
- +short int
- +smartnet_wav_read_sample(FILE *fp, int bytes_per_sample)
- +{
- + int16_t buf = 0;
- + size_t fresult;
- +
- + fresult = fread(&buf, bytes_per_sample, 1, fp);
- +
- + return (short) wav_to_host(buf);
- +}
- +
- +
- +bool
- +smartnet_wavheader_write(FILE *fp,
- + unsigned int sample_rate,
- + int nchans,
- + int bytes_per_sample)
- +{
- + const int header_len = 44;
- + char wav_hdr[header_len] = "RIFF\0\0\0\0WAVEfmt \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0data\0\0\0";
- + uint16_t nchans_f = (uint16_t) nchans;
- + uint32_t sample_rate_f = (uint32_t) sample_rate;
- + uint16_t block_align = bytes_per_sample * nchans;
- + uint32_t avg_bytes = sample_rate * block_align;
- + uint16_t bits_per_sample = bytes_per_sample * 8;
- +
- + nchans_f = host_to_wav(nchans_f);
- + sample_rate_f = host_to_wav(sample_rate_f);
- + block_align = host_to_wav(block_align);
- + avg_bytes = host_to_wav(avg_bytes);
- + bits_per_sample = host_to_wav(bits_per_sample);
- +
- + wav_hdr[16] = 0x10; // no extra bytes
- + wav_hdr[20] = 0x01; // no compression
- + memcpy((void *) (wav_hdr + 22), (void *) &nchans_f, 2);
- + memcpy((void *) (wav_hdr + 24), (void *) &sample_rate_f, 4);
- + memcpy((void *) (wav_hdr + 28), (void *) &avg_bytes, 4);
- + memcpy((void *) (wav_hdr + 32), (void *) &block_align, 2);
- + memcpy((void *) (wav_hdr + 34), (void *) &bits_per_sample, 2);
- +
- + fwrite(&wav_hdr, 1, header_len, fp);
- + if (ferror(fp)) {
- + return false;
- + }
- +
- + return true;
- +}
- +
- +
- +void
- +smartnet_wav_write_sample(FILE *fp, short int sample, int bytes_per_sample)
- +{
- + void *data_ptr;
- + unsigned char buf_8bit;
- + int16_t buf_16bit;
- +
- + if (bytes_per_sample == 1) {
- + buf_8bit = (unsigned char) sample;
- + data_ptr = (void *) &buf_8bit;
- + } else {
- + buf_16bit = host_to_wav((int16_t) sample);
- + data_ptr = (void *) &buf_16bit;
- + }
- +
- + fwrite(data_ptr, 1, bytes_per_sample, fp);
- +}
- +
- +
- +bool
- +smartnet_wavheader_complete(FILE *fp, unsigned int byte_count)
- +{
- + uint32_t chunk_size = (uint32_t) byte_count;
- + chunk_size = host_to_wav(chunk_size);
- +
- + fseek(fp, 40, SEEK_SET);
- + fwrite(&chunk_size, 1, 4, fp);
- +
- + chunk_size = (uint32_t) byte_count + 36; // fmt chunk and data header
- + chunk_size = host_to_wav(chunk_size);
- + fseek(fp, 4, SEEK_SET);
- +
- + fwrite(&chunk_size, 1, 4, fp);
- +
- + if (ferror(fp)) {
- + return false;
- + }
- +
- + return true;
- +}
- diff --git a/src/lib/smartnet_wavfile.h b/src/lib/smartnet_wavfile.h
- new file mode 100644
- index 0000000..2c70d0b
- --- /dev/null
- +++ b/src/lib/smartnet_wavfile.h
- @@ -0,0 +1,101 @@
- +/* -*- c++ -*- */
- +/*
- + * Copyright 2008 Free Software Foundation, Inc.
- + *
- + * This file is part of GNU Radio
- + *
- + * GNU Radio is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 3, or (at your option)
- + * any later version.
- + *
- + * GNU Radio is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with GNU Radio; see the file COPYING. If not, write to
- + * the Free Software Foundation, Inc., 51 Franklin Street,
- + * Boston, MA 02110-1301, USA.
- + */
- +
- +// This file stores all the RIFF file type knowledge for the gr_wavfile_*
- +// blocks.
- +
- +//#include <gr_core_api.h>
- +#include <cstdio>
- +
- +/*!
- + * \brief Read signal information from a given WAV file.
- + *
- + * \p fp File pointer to an opened, empty file.
- + * \p sample_rate Stores the sample rate [S/s]
- + * \p nchans Number of channels
- + * \p bytes_per_sample Bytes per sample, can either be 1 or 2 (corresponding to
- + * 8 or 16 bit samples, respectively)
- + * \p first_sample_pos Number of the first byte containing a sample. Use this
- + * with fseek() to jump from the end of the file to the first sample
- + * when in repeat mode.
- + * \p samples_per_chan Number of samples per channel
- + * \p normalize_fac The normalization factor with which you need to divide the
- + * integer values of the samples to get them within [-1;1]
- + * \p normalize_shift The value by which the sample values need to be shifted
- + * after normalization (reason being, 8-bit WAV files store samples as
- + * unsigned char and 16-bit as signed short int)
- + * \return True on a successful read, false if the file could not be read or is
- + * not a valid WAV file.
- + */
- +bool
- +smartnet_wavheader_parse(FILE *fp,
- + unsigned int &sample_rate,
- + int &nchans,
- + int &bytes_per_sample,
- + int &first_sample_pos,
- + unsigned int &samples_per_chan);
- +
- +
- +/*!
- + * \brief Read one sample from an open WAV file at the current position.
- + *
- + * Takes care of endianness.
- + */
- +short int
- +smartnet_wav_read_sample(FILE *fp, int bytes_per_sample);
- +
- +
- +/*!
- + * \brief Write a valid RIFF file header
- + *
- + * Note: Some header values are kept blank because they're usually not known
- + * a-priori (file and chunk lengths). Use smartnet_wavheader_complete() to fill
- + * these in.
- + */
- +bool
- +smartnet_wavheader_write(FILE *fp,
- + unsigned int sample_rate,
- + int nchans,
- + int bytes_per_sample);
- +
- +/*!
- + * \brief Write one sample to an open WAV file at the current position.
- + *
- + * Takes care of endianness.
- + */
- +void
- +smartnet_wav_write_sample(FILE *fp, short int sample, int bytes_per_sample);
- +
- +
- +/*!
- + * \brief Complete a WAV header
- + *
- + * Note: The stream position is changed during this function. If anything
- + * needs to be written to the WAV file after calling this function (which
- + * shouldn't happen), you need to fseek() to the end of the file (or
- + * whereever).
- + *
- + * \p fp File pointer to an open WAV file with a blank header
- + * \p byte_count Length of all samples written to the file in bytes.
- + */
- +bool
- +smartnet_wavheader_complete(FILE *fp, unsigned int byte_count);
- diff --git a/src/lib/smartnet_wavsink.cc b/src/lib/smartnet_wavsink.cc
- index bc75e0c..d795fdf 100644
- --- a/src/lib/smartnet_wavsink.cc
- +++ b/src/lib/smartnet_wavsink.cc
- @@ -26,7 +26,7 @@
- #include <smartnet_wavsink.h>
- #include <gr_io_signature.h>
- -#include <gri_wavfile.h>
- +#include <smartnet_wavfile.h>
- #include <stdexcept>
- #include <climits>
- #include <cstring>
- @@ -140,7 +140,7 @@ smartnet_wavsink::open(const char* filename)
- int new_nchans, new_bytes_per_sample, new_first_sample_pos;
- //validate the data, be sure it's set up the same as the current block (sample rate, mono/stereo, etc) and barf if it isn't
- - if (!gri_wavheader_parse(d_new_fp,
- + if (!smartnet_wavheader_parse(d_new_fp,
- new_sample_rate,
- new_nchans,
- new_bytes_per_sample,
- @@ -180,7 +180,7 @@ smartnet_wavsink::open(const char* filename)
- }
- d_updated = true;
- - if (!gri_wavheader_write(d_new_fp,
- + if (!smartnet_wavheader_write(d_new_fp,
- d_sample_rate,
- d_nchans,
- d_bytes_per_sample_new)) {
- @@ -211,7 +211,7 @@ void smartnet_wavsink::close_wav()
- //printf("Writing wav header with %f seconds of audio\n", ((float(d_sample_count)/d_sample_rate)/d_nchans)/d_bytes_per_sample);
- - if(!gri_wavheader_complete(d_fp, byte_count)) {
- + if(!smartnet_wavheader_complete(d_fp, byte_count)) {
- throw std::runtime_error("Error writing wav header\n");
- }
- @@ -256,7 +256,7 @@ smartnet_wavsink::work (int noutput_items,
- sample_buf_s = 0;
- }
- - gri_wav_write_sample(d_fp, sample_buf_s, d_bytes_per_sample);
- + smartnet_wav_write_sample(d_fp, sample_buf_s, d_bytes_per_sample);
- if (feof(d_fp) || ferror(d_fp)) {
- fprintf(stderr, "[%s] file i/o error\n", __FILE__);
- diff --git a/src/python/smartnet2logging_rtl.py b/src/python/smartnet2logging_rtl.py
- new file mode 100755
- index 0000000..7ef2f42
- --- /dev/null
- +++ b/src/python/smartnet2logging_rtl.py
- @@ -0,0 +1,277 @@
- +#!/usr/bin/env python
- +"""
- + This program decodes the Motorola SmartNet II trunking protocol from the control channel
- + Tune it to the control channel center freq, and it'll spit out the decoded packets.
- + In what format? Who knows.
- +
- + This program does not include audio output support. It logs channels to disk by talkgroup name. If you don't specify what talkgroups to log, it logs EVERYTHING.
- +"""
- +
- +from gnuradio import gr, gru, blks2, optfir, digital
- +from grc_gnuradio import blks2 as grc_blks2
- +from gnuradio import audio
- +from gnuradio import eng_notation
- +#from gnuradio import uhd
- +from fsk_demod import fsk_demod
- +from logging_receiver import logging_receiver
- +from optparse import OptionParser
- +from gnuradio.eng_option import eng_option
- +from gnuradio import smartnet
- +#from gnuradio.wxgui import slider
- +#from gnuradio.wxgui import stdgui2, fftsink2, form
- +import osmosdr
- +from gnuradio import digital
- +
- +#from pkt import *
- +import time
- +import gnuradio.gr.gr_threading as _threading
- +import csv
- +import os
- +
- +class top_block_runner(_threading.Thread):
- + def __init__(self, tb):
- + _threading.Thread.__init__(self)
- + self.setDaemon(1)
- + self.tb = tb
- + self.done = False
- + self.start()
- +
- + def run(self):
- + self.tb.run()
- + self.done = True
- +
- +class my_top_block(gr.top_block):
- + def __init__(self, options, queue):
- + gr.top_block.__init__(self)
- +
- + self.rtl = osmosdr.source_c( args="nchan=" + str(1) + " " + "" )
- + self.rtl.set_sample_rate(options.rate)
- + self.rtl.set_center_freq(options.centerfreq, 0)
- + self.rtl.set_freq_corr(options.ppm, 0)
- + self.rtl.set_gain_mode(1, 0)
- +
- + self.centerfreq = options.centerfreq
- + print "Tuning to: %fMHz" % (self.centerfreq - options.error)
- + if not(self.tune(options.centerfreq - options.error)):
- + print "Failed to set initial frequency"
- +
- + if options.gain is None: #set to halfway
- +# g = self.u.get_gain_range()
- +# options.gain = (g.start()+g.stop()) / 2.0
- + options.gain = 10
- + # TODO FIX^
- +
- + print "Setting gain to %i" % options.gain
- + self.rtl.set_gain(options.gain, 0)
- +
- + self.rate = options.rate
- +
- + print "Samples per second is %i" % self.rate
- +
- + self._syms_per_sec = 3600;
- +
- + options.audiorate = 11025
- + options.rate = self.rate
- +
- + options.samples_per_second = self.rate #yeah i know it's on the list
- + options.syms_per_sec = self._syms_per_sec
- + options.gain_mu = 0.01
- + options.mu=0.5
- + options.omega_relative_limit = 0.3
- + options.syms_per_sec = self._syms_per_sec
- + options.offset = options.centerfreq - options.freq
- + print "Control channel offset: %f" % options.offset
- +
- + self.demod = fsk_demod(options)
- + self.start_correlator = digital.correlate_access_code_bb("10101100",0) #should mark start of packet
- + self.smartnet_sync = smartnet.sync()
- + self.smartnet_deinterleave = smartnet.deinterleave()
- + self.smartnet_parity = smartnet.parity()
- + self.smartnet_crc = smartnet.crc()
- + self.smartnet_packetize = smartnet.packetize()
- + self.parse = smartnet.parse(queue) #packet-based. this simply posts lightly-formatted messages to the queue.
- +
- + self.connect(self.rtl, self.demod)
- +
- + self.connect(self.demod, self.start_correlator, self.smartnet_sync, self.smartnet_deinterleave, self.smartnet_parity, self.smartnet_crc, self.smartnet_packetize, self.parse)
- +
- +
- + def tune(self, freq):
- + result = self.rtl.set_center_freq(freq)
- + return True
- +
- +def getfreq(chanlist, cmd):
- + if chanlist is None: #if no chanlist file, make a guess. there are four extant bandplan schemes, and i believe this one is the most common.
- +# if cmd < 0x2d0:
- +# Changed for rebanding
- + if cmd < 0x1b8:
- + freq = float(cmd * 0.025 + 851.0125)
- + elif cmd < 0x230:
- + freq = float(cmd * 0.025 + 851.0125 - 10.9875)
- + else:
- + freq = None
- + else: #program your channel listings, get the right freqs.
- + if chanlist.get(str(cmd), None) is not None:
- + freq = float(chanlist[str(cmd)])
- + else:
- + freq = None
- +
- + return freq
- +
- +def parsefreq(s, chanlist):
- + retfreq = None
- + [address, groupflag, command] = s.split(",")
- + command = int(command)
- + address = int(address) & 0xFFF0
- + groupflag = bool(groupflag)
- +
- + if chanlist is None:
- + if command < 0x2d0:
- + retfreq = getfreq(chanlist, command)
- +
- + else:
- + if chanlist.get(str(command), None) is not None: #if it falls into the channel somewhere
- + retfreq = getfreq(chanlist, command)
- + return [retfreq, address] # mask so the squelch opens up on the entire group
- +
- +
- +
- +def main():
- + # Create Options Parser:
- + parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
- + expert_grp = parser.add_option_group("Expert")
- +
- + parser.add_option("-f", "--freq", type="eng_float", default=866.9625e6,
- + help="set control channel frequency to MHz [default=%default]", metavar="FREQ")
- + parser.add_option("-c", "--centerfreq", type="eng_float", default=867.5e6,
- + help="set center receive frequency to MHz [default=%default]. Set to center of 800MHz band for best results")
- + parser.add_option("-g", "--gain", type="int", default=None,
- + help="set RF gain", metavar="dB")
- + parser.add_option("-r", "--rate", type="eng_float", default=64e6/18,
- + help="set sample rate [default=%default]")
- +# parser.add_option("-b", "--bandwidth", type="eng_float", default=3e6,
- +# help="set bandwidth of DBS RX frond end [default=%default]")
- + parser.add_option("-C", "--chanlistfile", type="string", default=None,
- + help="read in list of Motorola channel frequencies (improves accuracy of frequency decoding) [default=%default]")
- + parser.add_option("-E", "--error", type="eng_float", default=0,
- + help="enter an offset error to compensate for USRP clock inaccuracy")
- + parser.add_option("-m", "--monitor", type="int", default=None,
- + help="monitor a specific talkgroup")
- + parser.add_option("-v", "--volume", type="eng_float", default=3.0,
- + help="set volume gain for audio output [default=%default]")
- + parser.add_option("-s", "--squelch", type="eng_float", default=28,
- + help="set audio squelch level (default=%default, play with it)")
- + parser.add_option("-D", "--directory", type="string", default="./log",
- + help="choose a directory in which to save log data [default=%default]")
- +# parser.add_option("-a", "--addr", type="string", default="",
- +# help="address options to pass to UHD")
- +# parser.add_option("-s", "--subdev", type="string",
- +# help="UHD subdev spec", default=None)
- +# parser.add_option("-A", "--antenna", type="string", default=None,
- +# help="select Rx Antenna where appropriate")
- +# FOR RTL
- + parser.add_option("-p", "--ppm", type="eng_float", default=0,
- + help="set RTL PPM frequency adjustment [default=%default]")
- +
- + #receive_path.add_options(parser, expert_grp)
- +
- + (options, args) = parser.parse_args ()
- +
- + if len(args) != 0:
- + parser.print_help(sys.stderr)
- + sys.exit(1)
- +
- +
- + if options.chanlistfile is not None:
- + clreader=csv.DictReader(open(options.chanlistfile), quotechar='"')
- + chanlist={"0": 0}
- + for record in clreader:
- + chanlist[record['channel']] = record['frequency']
- + else:
- + chanlist = None
- +
- + # build the graph
- + queue = gr.msg_queue()
- + tb = my_top_block(options, queue)
- +
- + runner = top_block_runner(tb)
- +
- + updaterate = 10 #main loop rate in Hz
- + audiologgers = [] #this is the list of active audio sinks.
- + rxfound = False #a flag to indicate whether or not an audio sink was found with the correct talkgroup ID; see below
- +
- +
- + try:
- + while 1:
- + if not queue.empty_p():
- + msg = queue.delete_head() # Blocking read
- + sentence = msg.to_string()
- +
- + [newfreq, newaddr] = parsefreq(sentence, chanlist)
- +
- + monaddr = newaddr & 0xFFF0 #last 8 bits are status flags for a given talkgroup
- +
- + if newfreq is not None and int(newfreq*1e6) == int(options.freq):
- + newfreq = None #don't log the audio from the trunk itself
- +
- + #we have a new frequency assignment. look through the list of audio logger objects and find if any of them have been allocated to it
- + rxfound = False
- +
- + for rx in audiologgers:
- +
- + #print "Logger info: %i @ %f idle for %fs" % (rx.talkgroup, rx.getfreq(options.centerfreq), rx.timeout()) #TODO: debug
- +
- + #first look through the list to find out if there is a receiver assigned to this talkgroup
- + if rx.talkgroup == monaddr: #here we've got one
- + if newfreq != rx.getfreq(options.centerfreq) and newfreq is not None: #we're on a new channel, though
- + rx.tuneoffset(newfreq, options.centerfreq)
- +
- + rx.unmute() #this should be unnecessary but it does update the timestamp
- + rxfound = True
- + #print "New transmission on TG %i, updating timestamp" % rx.talkgroup
- +
- + else:
- + if rx.getfreq(options.centerfreq) == newfreq: #a different talkgroup, but a new assignment on that freq! time to mute.
- + rx.mute()
- +
- + if rxfound is False and newfreq is not None: #no existing receiver for this talkgroup. time to create one.
- + #lock the flowgraph
- + tb.lock()
- + audiologgers.append( logging_receiver(newaddr, options) ) #create it
- + audiologgers[-1].tuneoffset(newfreq, options.centerfreq) #tune it
- + tb.connect(tb.rtl, audiologgers[-1]) #connect to the flowgraph
- + tb.unlock()
- + audiologgers[-1].unmute() #unmute it
- +
- + if newfreq is not None:
- + print "TG %i @ %f, %i active loggers" % (newaddr, newfreq, len(audiologgers))
- +
- +
- + else:
- + time.sleep(1.0/updaterate)
- +
- + for rx in audiologgers:
- + if rx.timeout() >= 5.0: #if this receiver has been muted more than 3 seconds
- + rx.close() #close the .wav file that the logger has been writing to
- + tb.lock()
- + tb.disconnect(rx)
- + tb.unlock()
- + audiologgers.remove(rx) #delete the audio logger object from the list
- +
- + except KeyboardInterrupt:
- + #perform cleanup: time to get out of Dodge
- + for rx in audiologgers: #you probably don't need to lock, disconnect, unlock, remove. but you might as well.
- + rx.close()
- + #tb.lock()
- + #tb.disconnect(rx)
- + #tb.unlock()
- + audiologgers.remove(rx)
- +
- + tb.stop()
- +
- + runner = None
- +
- +if __name__ == '__main__':
- + main()
- +
- +
- END_PATCH
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement