Adapt AFSK1200 AX.25 flowgraph to gr-soapy

This commit is contained in:
Manolis Surligas 2019-12-18 21:00:28 +02:00
parent 977f732b4d
commit 0ec7b29f93
2 changed files with 1374 additions and 4689 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +1,53 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##################################################
#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph # GNU Radio Python Flow Graph
# Title: AFSK1200 AX.25 decoder # Title: AFSK1200 AX.25 decoder
# Author: Manolis Surligas (surligas@gmail.com), Vardakis Giorgos (vardakis.grg@gmail.com) # Author: Manolis Surligas (surligas@gmail.com), Vardakis Giorgos (vardakis.grg@gmail.com)
# Description: AFSK1200 AX.25 decoder # Description: AFSK1200 AX.25 decoder
# GNU Radio version: 3.7.13.5 # GNU Radio version: 3.8.0.0
##################################################
from gnuradio import analog from gnuradio import analog
import math
from gnuradio import blocks from gnuradio import blocks
from gnuradio import digital from gnuradio import digital
from gnuradio import eng_notation
from gnuradio import filter from gnuradio import filter
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes from gnuradio.filter import firdes
from gnuradio.filter import pfb from gnuradio import gr
from optparse import OptionParser import sys
import math import signal
import osmosdr from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
import satnogs import satnogs
import time import soapy
class satnogs_afsk1200_ax25(gr.top_block): class satnogs_afsk1200_ax25(gr.top_block):
def __init__(self, antenna=satnogs.not_set_antenna, baudrate=1200.0, bb_gain=satnogs.not_set_rx_bb_gain, decoded_data_file_path='/tmp/.satnogs/data/data', dev_args=satnogs.not_set_dev_args, doppler_correction_per_sec=20, enable_iq_dump=0, file_path='test.wav', if_gain=satnogs.not_set_rx_if_gain, iq_file_path='/tmp/iq.dat', lo_offset=100e3, mark_frequency=2200.0, ppm=0, rf_gain=satnogs.not_set_rx_rf_gain, rigctl_port=4532, rx_freq=100e6, rx_sdr_device='usrpb200', samp_rate_rx=satnogs.not_set_samp_rate_rx, space_frequency=1200.0, udp_IP='127.0.0.1', udp_port=16887, waterfall_file_path='/tmp/waterfall.dat'): def __init__(self, antenna='', bw=0.0, decoded_data_file_path='/tmp/.satnogs/data/data', dev_args='', doppler_correction_per_sec=20, enable_iq_dump=0, file_path='test.wav', gain=0.0, iq_file_path='/tmp/iq.dat', lo_offset=100e3, mark_frequency=2200.0, rigctl_port=4532, rx_freq=100e6, samp_rate_rx=0.0, soapy_rx_device='driver=invalid', space_frequency=1200.0, udp_IP='127.0.0.1', udp_port=16887, waterfall_file_path='/tmp/waterfall.dat'):
gr.top_block.__init__(self, "AFSK1200 AX.25 decoder ") gr.top_block.__init__(self, "AFSK1200 AX.25 decoder ")
################################################## ##################################################
# Parameters # Parameters
################################################## ##################################################
self.antenna = antenna self.antenna = antenna
self.baudrate = baudrate self.bw = bw
self.bb_gain = bb_gain
self.decoded_data_file_path = decoded_data_file_path self.decoded_data_file_path = decoded_data_file_path
self.dev_args = dev_args self.dev_args = dev_args
self.doppler_correction_per_sec = doppler_correction_per_sec self.doppler_correction_per_sec = doppler_correction_per_sec
self.enable_iq_dump = enable_iq_dump self.enable_iq_dump = enable_iq_dump
self.file_path = file_path self.file_path = file_path
self.if_gain = if_gain self.gain = gain
self.iq_file_path = iq_file_path self.iq_file_path = iq_file_path
self.lo_offset = lo_offset self.lo_offset = lo_offset
self.mark_frequency = mark_frequency self.mark_frequency = mark_frequency
self.ppm = ppm
self.rf_gain = rf_gain
self.rigctl_port = rigctl_port self.rigctl_port = rigctl_port
self.rx_freq = rx_freq self.rx_freq = rx_freq
self.rx_sdr_device = rx_sdr_device
self.samp_rate_rx = samp_rate_rx self.samp_rate_rx = samp_rate_rx
self.soapy_rx_device = soapy_rx_device
self.space_frequency = space_frequency self.space_frequency = space_frequency
self.udp_IP = udp_IP self.udp_IP = udp_IP
self.udp_port = udp_port self.udp_port = udp_port
@ -63,63 +60,183 @@ class satnogs_afsk1200_ax25(gr.top_block):
self.variable_ax25_decoder_0 = variable_ax25_decoder_0 = satnogs.ax25_decoder_make('GND', 0, True, True, True, 512) self.variable_ax25_decoder_0 = variable_ax25_decoder_0 = satnogs.ax25_decoder_make('GND', 0, True, True, True, 512)
self.max_modulation_freq = max_modulation_freq = 3000 self.max_modulation_freq = max_modulation_freq = 3000
self.deviation = deviation = 5000 self.deviation = deviation = 5000
self.baud_rate = baud_rate = 1200 self.baudrate = baudrate = 1200
self.audio_samp_rate = audio_samp_rate = 48000 self.audio_samp_rate = audio_samp_rate = 48000
################################################## ##################################################
# Blocks # Blocks
################################################## ##################################################
self.satnogs_waterfall_sink_0 = satnogs.waterfall_sink(audio_samp_rate, 0.0, 10, 1024, waterfall_file_path, 1) self.soapy_source_0 = None
if "custom" == 'custom':
dev = soapy_rx_device
else:
dev = 'driver=' + "custom"
if "custom" == 'sdrplay':
f = 'if_mode=' + "Zero-IF" + ',' + 'agc_setpoint=' + str("-30") + ',' + 'biasT_ctrl=' + "True".lower() + ',' + 'rfnotch_ctrl=' + "False".lower() + ',' + 'dabnotch_ctrl=' + "False".lower() + ',' + str(dev_args)
f = f.replace('\"', '')
f = f.replace("\\'", '')
f = f.strip(',')
self.soapy_source_0 = soapy.source(1, dev, f, samp_rate_rx, "fc32")
else:
self.soapy_source_0 = soapy.source(1, dev, dev_args, samp_rate_rx, "fc32")
if 0 != 0:
self.soapy_source_0.set_master_clock_rate(0)
if len('') > 0:
self.soapy_source_0.set_clock_source('')
# Set up dc offsets
if "custom" != 'uhd':
if (self.soapy_source_0.hasDCOffset(0)):
self.soapy_source_0.set_dc_offset(0,0,False == 'True')
if (self.soapy_source_0.hasDCOffset(1)):
self.soapy_source_0.set_dc_offset(1,0,False == 'True')
# Setup IQ Balance
if "custom" != 'uhd':
if (self.soapy_source_0.hasIQBalance(0)):
self.soapy_source_0.set_iq_balance(0,0)
if (self.soapy_source_0.hasIQBalance(1)):
self.soapy_source_0.set_iq_balance(1,0)
# Setup Frequency correction
if (self.soapy_source_0.hasFrequencyCorrection(0)):
self.soapy_source_0.set_frequency_correction(0,0)
if (self.soapy_source_0.hasFrequencyCorrection(1)):
self.soapy_source_0.set_frequency_correction(1,0)
self.soapy_source_0.set_gain_mode(0,False)
self.soapy_source_0.set_gain_mode(1,False)
self.soapy_source_0.set_frequency(0, rx_freq - lo_offset)
self.soapy_source_0.set_frequency(1, 0)
# Made antenna sanity check more generic
antList = self.soapy_source_0.listAntennas(0)
if len(antList) > 1:
# If we have more than 1 possible antenna
if len(antenna) == 0 or antenna not in antList:
print("ERROR: Please define ant0 to an allowed antenna name.")
strAntList = str(antList).lstrip('(').rstrip(')').rstrip(',')
print("Allowed antennas: " + strAntList)
exit(0)
self.soapy_source_0.set_antenna(0,antenna)
if 1 > 1:
antList = self.soapy_source_0.listAntennas(1)
# If we have more than 1 possible antenna
if len(antList) > 1:
if len('RX2') == 0 or 'RX2' not in antList:
print("ERROR: Please define ant1 to an allowed antenna name.")
strAntList = str(antList).lstrip('(').rstrip(')').rstrip(',')
print("Allowed antennas: " + strAntList)
exit(0)
self.soapy_source_0.set_antenna(1,'RX2')
self.soapy_source_0.set_overall_gain(0,gain, False )
self.soapy_source_0.set_overall_gain(1,10, True )
# Prevent some weird double-gain setting issues for systems with an overall_gain setting
# noticed weird behavior with uhd
if "custom" == 'uhd' or "custom" == 'sidekiq' or "custom" == 'bladerf' or "custom" == 'lime':
self.soapy_source_0.set_gain(0,"PGA", 24, False )
self.soapy_source_0.set_gain(1,"PGA", 24, True )
else:
if "custom" == 'custom':
# If we're here and we're custom, let's still call overall gain
self.soapy_source_0.set_overall_gain(0,gain, False )
self.soapy_source_0.set_overall_gain(1,10, True )
self.soapy_source_0.set_gain(0,"LNA", 10, False )
self.soapy_source_0.set_gain(1,"LNA", 10, True )
self.soapy_source_0.set_gain(0,"TIA", 0, False )
self.soapy_source_0.set_gain(1,"TIA", 0, True )
self.soapy_source_0.set_gain(0,"MIX", 10, False )
self.soapy_source_0.set_gain(1,"MIX", 10, True )
self.soapy_source_0.set_gain(0,"VGA", 10, False )
self.soapy_source_0.set_gain(1,"VGA", 10, True )
# Only rtl-sdr uses TUNER, so just ch0
self.soapy_source_0.set_gain(0,"TUNER", 10, False )
# Only hackrf uses "AMP", so just ch0
self.soapy_source_0.set_gain(0,"AMP", 0, False )
# Only sdrplay uses IFGR so just ch0 for each
self.soapy_source_0.set_gain(0,"IFGR", 59, False )
self.soapy_source_0.set_gain(0,"RFGR", 9, False )
self.satnogs_waterfall_sink_0 = satnogs.waterfall_sink(audio_samp_rate, rx_freq, 10, 1024, waterfall_file_path, 1)
self.satnogs_udp_msg_sink_0_0 = satnogs.udp_msg_sink(udp_IP, udp_port, 1500) self.satnogs_udp_msg_sink_0_0 = satnogs.udp_msg_sink(udp_IP, udp_port, 1500)
self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, int(1000.0/doppler_correction_per_sec) + 1, 1500) self.satnogs_tcp_rigctl_msg_source_0 = satnogs.tcp_rigctl_msg_source("127.0.0.1", rigctl_port, False, int(1000.0/doppler_correction_per_sec) + 1, 1500)
self.satnogs_ogg_encoder_0 = satnogs.ogg_encoder(file_path, audio_samp_rate, 1.0) self.satnogs_ogg_encoder_0 = satnogs.ogg_encoder(file_path, audio_samp_rate, 1.0)
self.satnogs_iq_sink_0 = satnogs.iq_sink(16768, iq_file_path, False, enable_iq_dump) self.satnogs_iq_sink_0 = satnogs.iq_sink(16768, iq_file_path, False, 1)
self.satnogs_frame_file_sink_0_1_0 = satnogs.frame_file_sink(decoded_data_file_path, 0) self.satnogs_frame_file_sink_0_1_0 = satnogs.frame_file_sink(decoded_data_file_path, 0)
self.satnogs_frame_decoder_0_0_0 = satnogs.frame_decoder(variable_ax25_decoder_0_0, gr.sizeof_char) self.satnogs_frame_decoder_0_0_0 = satnogs.frame_decoder(variable_ax25_decoder_0_0, 1 * 1)
self.satnogs_frame_decoder_0_0 = satnogs.frame_decoder(variable_ax25_decoder_0, gr.sizeof_char) self.satnogs_frame_decoder_0_0 = satnogs.frame_decoder(variable_ax25_decoder_0, 1 * 1)
self.satnogs_coarse_doppler_correction_cc_0 = satnogs.coarse_doppler_correction_cc(rx_freq, satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx)) self.satnogs_doppler_compensation_0 = satnogs.doppler_compensation(samp_rate_rx, rx_freq, lo_offset, audio_samp_rate, 1)
self.pfb_arb_resampler_xxx_0 = pfb.arb_resampler_ccf( self.low_pass_filter_2_0 = filter.fir_filter_fff(
audio_samp_rate/satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx), 1,
taps=None, firdes.low_pass(
flt_size=32) 1,
self.pfb_arb_resampler_xxx_0.declare_sample_delay(0) baudrate*2,
baudrate /2+ 500 /2,
self.osmosdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + satnogs.handle_rx_dev_args(rx_sdr_device, dev_args) ) 500,
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx)) firdes.WIN_HAMMING,
self.osmosdr_source_0.set_center_freq(rx_freq - lo_offset, 0) 6.76))
self.osmosdr_source_0.set_freq_corr(ppm, 0) self.low_pass_filter_1 = filter.fir_filter_ccf(
self.osmosdr_source_0.set_dc_offset_mode(2, 0) 20,
self.osmosdr_source_0.set_iq_balance_mode(0, 0) firdes.low_pass(
self.osmosdr_source_0.set_gain_mode(False, 0) 1,
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(rx_sdr_device, rf_gain), 0) audio_samp_rate,
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(rx_sdr_device, if_gain), 0) (mark_frequency - space_frequency)/2.0 + 250,
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(rx_sdr_device, bb_gain), 0) 500,
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(rx_sdr_device, antenna), 0) firdes.WIN_HAMMING,
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx), 0) 6.76))
self.low_pass_filter_0_0 = filter.fir_filter_ccf(
self.low_pass_filter_2_0 = filter.fir_filter_fff(1, firdes.low_pass( 1,
1, baudrate*2, baudrate /2+ 500 /2, 500, firdes.WIN_HAMMING, 6.76)) firdes.low_pass(
self.low_pass_filter_1 = filter.fir_filter_ccf(20, firdes.low_pass( 1,
1, audio_samp_rate, (mark_frequency - space_frequency)/2.0 + 250, 500, firdes.WIN_HAMMING, 6.76)) audio_samp_rate,
self.low_pass_filter_0 = filter.fir_filter_ccf(1, firdes.low_pass( (deviation+max_modulation_freq) * 1.25,
1, audio_samp_rate, deviation+max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76)) 3e3,
self.digital_clock_recovery_mm_xx_0 = digital.clock_recovery_mm_ff((48e3/20)/baud_rate, 2*math.pi/100.0, 0.5, 0.5/8.0, 0.01) firdes.WIN_HAMMING,
6.76))
self.low_pass_filter_0 = filter.fir_filter_ccf(
1,
firdes.low_pass(
1,
audio_samp_rate,
deviation+max_modulation_freq,
1000,
firdes.WIN_HAMMING,
6.76))
self.digital_clock_recovery_mm_xx_0 = digital.clock_recovery_mm_ff((48e3/20)/baudrate, 2*math.pi/100.0, 0.5, 0.5/8.0, 0.01)
self.digital_binary_slicer_fb_0 = digital.binary_slicer_fb() self.digital_binary_slicer_fb_0 = digital.binary_slicer_fb()
self.dc_blocker_xx_0_0 = filter.dc_blocker_ff(1024, True) self.dc_blocker_xx_0_0 = filter.dc_blocker_ff(1024, True)
self.dc_blocker_xx_0 = filter.dc_blocker_ff(1024, True) self.dc_blocker_xx_0 = filter.dc_blocker_ff(1024, True)
self.blocks_vco_c_0 = blocks.vco_c(audio_samp_rate, -audio_samp_rate, 1.0) self.blocks_vco_c_0 = blocks.vco_c(audio_samp_rate, -audio_samp_rate, 1.0)
self.blocks_rotator_cc_0 = blocks.rotator_cc(-2.0 * math.pi * (lo_offset / satnogs.handle_samp_rate_rx(rx_sdr_device, samp_rate_rx))) self.blocks_rotator_cc_0 = blocks.rotator_cc(-2.0 * math.pi * ( ((1200 + 2200) / 2) / audio_samp_rate))
self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1) self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1)
self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
self.blocks_moving_average_xx_0 = blocks.moving_average_ff(1024, 1.0/1024.0, 4096, 1) self.blocks_moving_average_xx_0 = blocks.moving_average_ff(1024, 1.0/1024.0, 4096, 1)
self.blocks_float_to_complex_0 = blocks.float_to_complex(1) self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, 1024/2) self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, 1024//2)
self.band_pass_filter_0 = filter.fir_filter_fff(1, firdes.band_pass( self.band_pass_filter_0 = filter.fir_filter_fff(
1, audio_samp_rate, 1000, 2400, 400, firdes.WIN_HAMMING, 6.76)) 1,
self.analog_sig_source_x_0 = analog.sig_source_c(audio_samp_rate, analog.GR_COS_WAVE, -(1200 + 2200) / 2, 1, 0) firdes.band_pass(
1,
audio_samp_rate,
1000,
2400,
400,
firdes.WIN_HAMMING,
6.76))
self.analog_quadrature_demod_cf_0_0_0_0 = analog.quadrature_demod_cf(1.0) self.analog_quadrature_demod_cf_0_0_0_0 = analog.quadrature_demod_cf(1.0)
self.analog_quadrature_demod_cf_0_0 = analog.quadrature_demod_cf((2*math.pi*deviation)/audio_samp_rate) self.analog_quadrature_demod_cf_0_0 = analog.quadrature_demod_cf((2*math.pi*deviation)/audio_samp_rate)
self.analog_quadrature_demod_cf_0 = analog.quadrature_demod_cf(((audio_samp_rate/20) / baud_rate)/(math.pi*1)) self.analog_quadrature_demod_cf_0 = analog.quadrature_demod_cf(((audio_samp_rate/20) / baudrate)/(math.pi*1))
@ -130,19 +247,17 @@ class satnogs_afsk1200_ax25(gr.top_block):
self.msg_connect((self.satnogs_frame_decoder_0_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in')) self.msg_connect((self.satnogs_frame_decoder_0_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in'))
self.msg_connect((self.satnogs_frame_decoder_0_0_0, 'out'), (self.satnogs_frame_file_sink_0_1_0, 'frame')) self.msg_connect((self.satnogs_frame_decoder_0_0_0, 'out'), (self.satnogs_frame_file_sink_0_1_0, 'frame'))
self.msg_connect((self.satnogs_frame_decoder_0_0_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in')) self.msg_connect((self.satnogs_frame_decoder_0_0_0, 'out'), (self.satnogs_udp_msg_sink_0_0, 'in'))
self.msg_connect((self.satnogs_tcp_rigctl_msg_source_0, 'freq'), (self.satnogs_coarse_doppler_correction_cc_0, 'freq')) self.msg_connect((self.satnogs_tcp_rigctl_msg_source_0, 'freq'), (self.satnogs_doppler_compensation_0, 'doppler'))
self.connect((self.analog_quadrature_demod_cf_0, 0), (self.dc_blocker_xx_0_0, 0)) self.connect((self.analog_quadrature_demod_cf_0, 0), (self.dc_blocker_xx_0_0, 0))
self.connect((self.analog_quadrature_demod_cf_0_0, 0), (self.band_pass_filter_0, 0)) self.connect((self.analog_quadrature_demod_cf_0_0, 0), (self.band_pass_filter_0, 0))
self.connect((self.analog_quadrature_demod_cf_0_0, 0), (self.satnogs_ogg_encoder_0, 0)) self.connect((self.analog_quadrature_demod_cf_0_0, 0), (self.satnogs_ogg_encoder_0, 0))
self.connect((self.analog_quadrature_demod_cf_0_0_0_0, 0), (self.blocks_moving_average_xx_0, 0)) self.connect((self.analog_quadrature_demod_cf_0_0_0_0, 0), (self.blocks_moving_average_xx_0, 0))
self.connect((self.analog_sig_source_x_0, 0), (self.blocks_multiply_xx_0, 1))
self.connect((self.band_pass_filter_0, 0), (self.dc_blocker_xx_0, 0)) self.connect((self.band_pass_filter_0, 0), (self.dc_blocker_xx_0, 0))
self.connect((self.blocks_delay_0, 0), (self.blocks_multiply_xx_0_0, 0)) self.connect((self.blocks_delay_0, 0), (self.blocks_multiply_xx_0_0, 0))
self.connect((self.blocks_float_to_complex_0, 0), (self.blocks_multiply_xx_0, 0)) self.connect((self.blocks_float_to_complex_0, 0), (self.blocks_rotator_cc_0, 0))
self.connect((self.blocks_moving_average_xx_0, 0), (self.blocks_vco_c_0, 0)) self.connect((self.blocks_moving_average_xx_0, 0), (self.blocks_vco_c_0, 0))
self.connect((self.blocks_multiply_xx_0, 0), (self.low_pass_filter_1, 0))
self.connect((self.blocks_multiply_xx_0_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.blocks_multiply_xx_0_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.blocks_rotator_cc_0, 0), (self.satnogs_coarse_doppler_correction_cc_0, 0)) self.connect((self.blocks_rotator_cc_0, 0), (self.low_pass_filter_1, 0))
self.connect((self.blocks_vco_c_0, 0), (self.blocks_multiply_xx_0_0, 1)) self.connect((self.blocks_vco_c_0, 0), (self.blocks_multiply_xx_0_0, 1))
self.connect((self.dc_blocker_xx_0, 0), (self.blocks_float_to_complex_0, 0)) self.connect((self.dc_blocker_xx_0, 0), (self.blocks_float_to_complex_0, 0))
self.connect((self.dc_blocker_xx_0_0, 0), (self.low_pass_filter_2_0, 0)) self.connect((self.dc_blocker_xx_0_0, 0), (self.low_pass_filter_2_0, 0))
@ -150,35 +265,28 @@ class satnogs_afsk1200_ax25(gr.top_block):
self.connect((self.digital_binary_slicer_fb_0, 0), (self.satnogs_frame_decoder_0_0_0, 0)) self.connect((self.digital_binary_slicer_fb_0, 0), (self.satnogs_frame_decoder_0_0_0, 0))
self.connect((self.digital_clock_recovery_mm_xx_0, 0), (self.digital_binary_slicer_fb_0, 0)) self.connect((self.digital_clock_recovery_mm_xx_0, 0), (self.digital_binary_slicer_fb_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.analog_quadrature_demod_cf_0_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.analog_quadrature_demod_cf_0_0, 0))
self.connect((self.low_pass_filter_0_0, 0), (self.analog_quadrature_demod_cf_0_0_0_0, 0))
self.connect((self.low_pass_filter_1, 0), (self.analog_quadrature_demod_cf_0, 0)) self.connect((self.low_pass_filter_1, 0), (self.analog_quadrature_demod_cf_0, 0))
self.connect((self.low_pass_filter_2_0, 0), (self.digital_clock_recovery_mm_xx_0, 0)) self.connect((self.low_pass_filter_2_0, 0), (self.digital_clock_recovery_mm_xx_0, 0))
self.connect((self.osmosdr_source_0, 0), (self.blocks_rotator_cc_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.blocks_delay_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.analog_quadrature_demod_cf_0_0_0_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.low_pass_filter_0_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.blocks_delay_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.satnogs_iq_sink_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.satnogs_iq_sink_0, 0)) self.connect((self.satnogs_doppler_compensation_0, 0), (self.satnogs_waterfall_sink_0, 0))
self.connect((self.pfb_arb_resampler_xxx_0, 0), (self.satnogs_waterfall_sink_0, 0)) self.connect((self.soapy_source_0, 0), (self.satnogs_doppler_compensation_0, 0))
self.connect((self.satnogs_coarse_doppler_correction_cc_0, 0), (self.pfb_arb_resampler_xxx_0, 0))
def get_antenna(self): def get_antenna(self):
return self.antenna return self.antenna
def set_antenna(self, antenna): def set_antenna(self, antenna):
self.antenna = antenna self.antenna = antenna
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(self.rx_sdr_device, self.antenna), 0) self.soapy_source_0.set_antenna(0,self.antenna)
def get_baudrate(self): def get_bw(self):
return self.baudrate return self.bw
def set_baudrate(self, baudrate): def set_bw(self, bw):
self.baudrate = baudrate self.bw = bw
self.low_pass_filter_2_0.set_taps(firdes.low_pass(1, self.baudrate*2, self.baudrate /2+ 500 /2, 500, firdes.WIN_HAMMING, 6.76)) self.soapy_source_0.set_bandwidth(0,self.bw)
def get_bb_gain(self):
return self.bb_gain
def set_bb_gain(self, bb_gain):
self.bb_gain = bb_gain
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(self.rx_sdr_device, self.bb_gain), 0)
def get_decoded_data_file_path(self): def get_decoded_data_file_path(self):
return self.decoded_data_file_path return self.decoded_data_file_path
@ -210,26 +318,26 @@ class satnogs_afsk1200_ax25(gr.top_block):
def set_file_path(self, file_path): def set_file_path(self, file_path):
self.file_path = file_path self.file_path = file_path
def get_if_gain(self): def get_gain(self):
return self.if_gain return self.gain
def set_if_gain(self, if_gain): def set_gain(self, gain):
self.if_gain = if_gain self.gain = gain
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(self.rx_sdr_device, self.if_gain), 0) self.soapy_source_0.set_overall_gain(0,self.gain, False )
def get_iq_file_path(self): def get_iq_file_path(self):
return self.iq_file_path return self.iq_file_path
def set_iq_file_path(self, iq_file_path): def set_iq_file_path(self, iq_file_path):
self.iq_file_path = iq_file_path self.iq_file_path = iq_file_path
self.satnogs_iq_sink_0.open(self.iq_file_path)
def get_lo_offset(self): def get_lo_offset(self):
return self.lo_offset return self.lo_offset
def set_lo_offset(self, lo_offset): def set_lo_offset(self, lo_offset):
self.lo_offset = lo_offset self.lo_offset = lo_offset
self.osmosdr_source_0.set_center_freq(self.rx_freq - self.lo_offset, 0) self.soapy_source_0.set_frequency(0, self.rx_freq - self.lo_offset)
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def get_mark_frequency(self): def get_mark_frequency(self):
return self.mark_frequency return self.mark_frequency
@ -238,20 +346,6 @@ class satnogs_afsk1200_ax25(gr.top_block):
self.mark_frequency = mark_frequency self.mark_frequency = mark_frequency
self.low_pass_filter_1.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.mark_frequency - self.space_frequency)/2.0 + 250, 500, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_1.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.mark_frequency - self.space_frequency)/2.0 + 250, 500, firdes.WIN_HAMMING, 6.76))
def get_ppm(self):
return self.ppm
def set_ppm(self, ppm):
self.ppm = ppm
self.osmosdr_source_0.set_freq_corr(self.ppm, 0)
def get_rf_gain(self):
return self.rf_gain
def set_rf_gain(self, rf_gain):
self.rf_gain = rf_gain
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(self.rx_sdr_device, self.rf_gain), 0)
def get_rigctl_port(self): def get_rigctl_port(self):
return self.rigctl_port return self.rigctl_port
@ -263,32 +357,19 @@ class satnogs_afsk1200_ax25(gr.top_block):
def set_rx_freq(self, rx_freq): def set_rx_freq(self, rx_freq):
self.rx_freq = rx_freq self.rx_freq = rx_freq
self.satnogs_coarse_doppler_correction_cc_0.set_new_freq_locked(self.rx_freq) self.soapy_source_0.set_frequency(0, self.rx_freq - self.lo_offset)
self.osmosdr_source_0.set_center_freq(self.rx_freq - self.lo_offset, 0)
def get_rx_sdr_device(self):
return self.rx_sdr_device
def set_rx_sdr_device(self, rx_sdr_device):
self.rx_sdr_device = rx_sdr_device
self.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_gain(satnogs.handle_rx_rf_gain(self.rx_sdr_device, self.rf_gain), 0)
self.osmosdr_source_0.set_if_gain(satnogs.handle_rx_if_gain(self.rx_sdr_device, self.if_gain), 0)
self.osmosdr_source_0.set_bb_gain(satnogs.handle_rx_bb_gain(self.rx_sdr_device, self.bb_gain), 0)
self.osmosdr_source_0.set_antenna(satnogs.handle_rx_antenna(self.rx_sdr_device, self.antenna), 0)
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx), 0)
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def get_samp_rate_rx(self): def get_samp_rate_rx(self):
return self.samp_rate_rx return self.samp_rate_rx
def set_samp_rate_rx(self, samp_rate_rx): def set_samp_rate_rx(self, samp_rate_rx):
self.samp_rate_rx = samp_rate_rx self.samp_rate_rx = samp_rate_rx
self.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx))
self.osmosdr_source_0.set_sample_rate(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)) def get_soapy_rx_device(self):
self.osmosdr_source_0.set_bandwidth(satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx), 0) return self.soapy_rx_device
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * (self.lo_offset / satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)))
def set_soapy_rx_device(self, soapy_rx_device):
self.soapy_rx_device = soapy_rx_device
def get_space_frequency(self): def get_space_frequency(self):
return self.space_frequency return self.space_frequency
@ -333,114 +414,116 @@ class satnogs_afsk1200_ax25(gr.top_block):
def set_max_modulation_freq(self, max_modulation_freq): def set_max_modulation_freq(self, max_modulation_freq):
self.max_modulation_freq = max_modulation_freq self.max_modulation_freq = max_modulation_freq
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.deviation+self.max_modulation_freq) * 1.25, 3e3, firdes.WIN_HAMMING, 6.76))
def get_deviation(self): def get_deviation(self):
return self.deviation return self.deviation
def set_deviation(self, deviation): def set_deviation(self, deviation):
self.deviation = deviation self.deviation = deviation
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76))
self.analog_quadrature_demod_cf_0_0.set_gain((2*math.pi*self.deviation)/self.audio_samp_rate) self.analog_quadrature_demod_cf_0_0.set_gain((2*math.pi*self.deviation)/self.audio_samp_rate)
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.deviation+self.max_modulation_freq) * 1.25, 3e3, firdes.WIN_HAMMING, 6.76))
def get_baud_rate(self): def get_baudrate(self):
return self.baud_rate return self.baudrate
def set_baud_rate(self, baud_rate): def set_baudrate(self, baudrate):
self.baud_rate = baud_rate self.baudrate = baudrate
self.digital_clock_recovery_mm_xx_0.set_omega((48e3/20)/self.baud_rate) self.analog_quadrature_demod_cf_0.set_gain(((self.audio_samp_rate/20) / self.baudrate)/(math.pi*1))
self.analog_quadrature_demod_cf_0.set_gain(((self.audio_samp_rate/20) / self.baud_rate)/(math.pi*1)) self.digital_clock_recovery_mm_xx_0.set_omega((48e3/20)/self.baudrate)
self.low_pass_filter_2_0.set_taps(firdes.low_pass(1, self.baudrate*2, self.baudrate /2+ 500 /2, 500, firdes.WIN_HAMMING, 6.76))
def get_audio_samp_rate(self): def get_audio_samp_rate(self):
return self.audio_samp_rate return self.audio_samp_rate
def set_audio_samp_rate(self, audio_samp_rate): def set_audio_samp_rate(self, audio_samp_rate):
self.audio_samp_rate = audio_samp_rate self.audio_samp_rate = audio_samp_rate
self.pfb_arb_resampler_xxx_0.set_rate(self.audio_samp_rate/satnogs.handle_samp_rate_rx(self.rx_sdr_device, self.samp_rate_rx)) self.analog_quadrature_demod_cf_0.set_gain(((self.audio_samp_rate/20) / self.baudrate)/(math.pi*1))
self.low_pass_filter_1.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.mark_frequency - self.space_frequency)/2.0 + 250, 500, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76))
self.band_pass_filter_0.set_taps(firdes.band_pass(1, self.audio_samp_rate, 1000, 2400, 400, firdes.WIN_HAMMING, 6.76))
self.analog_sig_source_x_0.set_sampling_freq(self.audio_samp_rate)
self.analog_quadrature_demod_cf_0_0.set_gain((2*math.pi*self.deviation)/self.audio_samp_rate) self.analog_quadrature_demod_cf_0_0.set_gain((2*math.pi*self.deviation)/self.audio_samp_rate)
self.analog_quadrature_demod_cf_0.set_gain(((self.audio_samp_rate/20) / self.baud_rate)/(math.pi*1)) self.band_pass_filter_0.set_taps(firdes.band_pass(1, self.audio_samp_rate, 1000, 2400, 400, firdes.WIN_HAMMING, 6.76))
self.blocks_rotator_cc_0.set_phase_inc(-2.0 * math.pi * ( ((1200 + 2200) / 2) / self.audio_samp_rate))
self.low_pass_filter_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, self.deviation+self.max_modulation_freq, 1000, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_0_0.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.deviation+self.max_modulation_freq) * 1.25, 3e3, firdes.WIN_HAMMING, 6.76))
self.low_pass_filter_1.set_taps(firdes.low_pass(1, self.audio_samp_rate, (self.mark_frequency - self.space_frequency)/2.0 + 250, 500, firdes.WIN_HAMMING, 6.76))
def argument_parser(): def argument_parser():
description = 'AFSK1200 AX.25 decoder' description = 'AFSK1200 AX.25 decoder'
parser = OptionParser(usage="%prog: [options]", option_class=eng_option, description=description) parser = ArgumentParser(description=description)
parser.add_option( parser.add_argument(
"", "--antenna", dest="antenna", type="string", default=satnogs.not_set_antenna, "--antenna", dest="antenna", type=str, default='',
help="Set antenna [default=%default]") help="Set antenna [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--baudrate", dest="baudrate", type="eng_float", default=eng_notation.num_to_str(1200.0), "--bw", dest="bw", type=eng_float, default="0.0",
help="Set baudrate [default=%default]") help="Set Bandwidth [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--bb-gain", dest="bb_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_bb_gain), "--decoded-data-file-path", dest="decoded_data_file_path", type=str, default='/tmp/.satnogs/data/data',
help="Set bb_gain [default=%default]") help="Set decoded_data_file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--decoded-data-file-path", dest="decoded_data_file_path", type="string", default='/tmp/.satnogs/data/data', "--dev-args", dest="dev_args", type=str, default='',
help="Set decoded_data_file_path [default=%default]") help="Set Device arguments [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--dev-args", dest="dev_args", type="string", default=satnogs.not_set_dev_args, "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type=intx, default=20,
help="Set dev_args [default=%default]") help="Set doppler_correction_per_sec [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--doppler-correction-per-sec", dest="doppler_correction_per_sec", type="intx", default=20, "--enable-iq-dump", dest="enable_iq_dump", type=intx, default=0,
help="Set doppler_correction_per_sec [default=%default]") help="Set enable_iq_dump [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--enable-iq-dump", dest="enable_iq_dump", type="intx", default=0, "--file-path", dest="file_path", type=str, default='test.wav',
help="Set enable_iq_dump [default=%default]") help="Set file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--file-path", dest="file_path", type="string", default='test.wav', "--gain", dest="gain", type=eng_float, default="0.0",
help="Set file_path [default=%default]") help="Set gain [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--if-gain", dest="if_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_if_gain), "--iq-file-path", dest="iq_file_path", type=str, default='/tmp/iq.dat',
help="Set if_gain [default=%default]") help="Set iq_file_path [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--iq-file-path", dest="iq_file_path", type="string", default='/tmp/iq.dat', "--lo-offset", dest="lo_offset", type=eng_float, default="100.0k",
help="Set iq_file_path [default=%default]") help="Set lo_offset [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--lo-offset", dest="lo_offset", type="eng_float", default=eng_notation.num_to_str(100e3), "--mark-frequency", dest="mark_frequency", type=eng_float, default="2.2k",
help="Set lo_offset [default=%default]") help="Set mark_frequency [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--mark-frequency", dest="mark_frequency", type="eng_float", default=eng_notation.num_to_str(2200.0), "--rigctl-port", dest="rigctl_port", type=intx, default=4532,
help="Set mark_frequency [default=%default]") help="Set rigctl_port [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--ppm", dest="ppm", type="intx", default=0, "--rx-freq", dest="rx_freq", type=eng_float, default="100.0M",
help="Set ppm [default=%default]") help="Set rx_freq [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rf-gain", dest="rf_gain", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_rx_rf_gain), "--samp-rate-rx", dest="samp_rate_rx", type=eng_float, default="0.0",
help="Set rf_gain [default=%default]") help="Set Device Sampling rate [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rigctl-port", dest="rigctl_port", type="intx", default=4532, "--soapy-rx-device", dest="soapy_rx_device", type=str, default='driver=invalid',
help="Set rigctl_port [default=%default]") help="Set soapy_rx_device [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rx-freq", dest="rx_freq", type="eng_float", default=eng_notation.num_to_str(100e6), "--space-frequency", dest="space_frequency", type=eng_float, default="1.2k",
help="Set rx_freq [default=%default]") help="Set space_frequency [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--rx-sdr-device", dest="rx_sdr_device", type="string", default='usrpb200', "--udp-IP", dest="udp_IP", type=str, default='127.0.0.1',
help="Set rx_sdr_device [default=%default]") help="Set udp_IP [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--samp-rate-rx", dest="samp_rate_rx", type="eng_float", default=eng_notation.num_to_str(satnogs.not_set_samp_rate_rx), "--udp-port", dest="udp_port", type=intx, default=16887,
help="Set samp_rate_rx [default=%default]") help="Set udp_port [default=%(default)r]")
parser.add_option( parser.add_argument(
"", "--space-frequency", dest="space_frequency", type="eng_float", default=eng_notation.num_to_str(1200.0), "--waterfall-file-path", dest="waterfall_file_path", type=str, default='/tmp/waterfall.dat',
help="Set space_frequency [default=%default]") help="Set waterfall_file_path [default=%(default)r]")
parser.add_option(
"", "--udp-IP", dest="udp_IP", type="string", default='127.0.0.1',
help="Set udp_IP [default=%default]")
parser.add_option(
"", "--udp-port", dest="udp_port", type="intx", default=16887,
help="Set udp_port [default=%default]")
parser.add_option(
"", "--waterfall-file-path", dest="waterfall_file_path", type="string", default='/tmp/waterfall.dat',
help="Set waterfall_file_path [default=%default]")
return parser return parser
def main(top_block_cls=satnogs_afsk1200_ax25, options=None): def main(top_block_cls=satnogs_afsk1200_ax25, options=None):
if options is None: if options is None:
options, _ = argument_parser().parse_args() options = argument_parser().parse_args()
tb = top_block_cls(antenna=options.antenna, bw=options.bw, decoded_data_file_path=options.decoded_data_file_path, dev_args=options.dev_args, doppler_correction_per_sec=options.doppler_correction_per_sec, enable_iq_dump=options.enable_iq_dump, file_path=options.file_path, gain=options.gain, iq_file_path=options.iq_file_path, lo_offset=options.lo_offset, mark_frequency=options.mark_frequency, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, samp_rate_rx=options.samp_rate_rx, soapy_rx_device=options.soapy_rx_device, space_frequency=options.space_frequency, udp_IP=options.udp_IP, udp_port=options.udp_port, waterfall_file_path=options.waterfall_file_path)
def sig_handler(sig=None, frame=None):
tb.stop()
tb.wait()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb = top_block_cls(antenna=options.antenna, baudrate=options.baudrate, bb_gain=options.bb_gain, decoded_data_file_path=options.decoded_data_file_path, dev_args=options.dev_args, doppler_correction_per_sec=options.doppler_correction_per_sec, enable_iq_dump=options.enable_iq_dump, file_path=options.file_path, if_gain=options.if_gain, iq_file_path=options.iq_file_path, lo_offset=options.lo_offset, mark_frequency=options.mark_frequency, ppm=options.ppm, rf_gain=options.rf_gain, rigctl_port=options.rigctl_port, rx_freq=options.rx_freq, rx_sdr_device=options.rx_sdr_device, samp_rate_rx=options.samp_rate_rx, space_frequency=options.space_frequency, udp_IP=options.udp_IP, udp_port=options.udp_port, waterfall_file_path=options.waterfall_file_path)
tb.start() tb.start()
tb.wait() tb.wait()