diff --git a/dvbs-tx.py b/dvbs-tx.py
new file mode 100755
index 0000000..c9537c9
--- /dev/null
+++ b/dvbs-tx.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env /usr/bin/python
+
+# Copyright 2015 Edouard Griffiths, F4EXB
+#
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see .
+
+from gnuradio import blocks
+from gnuradio import digital
+from gnuradio import fft
+from gnuradio import gr
+from gnuradio import filter
+from gnuradio.filter import firdes
+from gnuradio import trellis
+from gnuradio.fft import window
+import dvbs
+import osmosdr
+import sys
+from optparse import OptionParser
+
+half_bws = [750000, 875000, 1250000, 1375000, 1500000, 1920000, 2500000, 2750000, 3000000, 3500000, 4375000, 5000000, 6000000, 7000000, 10000000, 14000000]
+
+# ======================================================================
+
+# ----------------------------------------------------------------------
+def getInputFromDict(input_dict, input_key):
+# ----------------------------------------------------------------------
+ if input_key in input_dict:
+ return input_dict[input_key]
+ else:
+ return None
+
+# ----------------------------------------------------------------------
+def getInputOptions():
+# ----------------------------------------------------------------------
+ default_ts_file = "/tmp/in.fifo"
+ default_freq = 1.27e9
+ symbol_rates = {"160k": 160000, "400k": 400000, "1M": 1000000, "1.5M": 1500000, "2M": 2000000}
+ default_txvga_gains_str = "-4,20"
+
+ parser = OptionParser(usage="usage: %%prog -r [-d [-f] [-q]] [-a] [-H]\n\n%s")
+ parser.add_option("-i", "--ts-file", dest="ts_file", help="Input transport stream file or FIFO (default %s)" % default_ts_file, metavar="DATA_FILE", type="string")
+ parser.add_option("-o", "--output-file", dest="out_file", help="Output complex samples file (default None)", metavar="OUTPUT_FILE", type="string")
+ parser.add_option("-f", "--frequency", dest="freq", help="Transmit center frequency in Hz (default %.3e)" % default_freq, metavar="FREQUENCY", type="float")
+ parser.add_option("-s", "--symbol-rate", dest="symbol_rate_str", help="Symbol rate: %s (default 1M)" % symbol_rates.keys(), metavar="SYMBOL_RATE", type="string")
+ parser.add_option("-G", "--txvga-gains", dest="txvga_gains_str", help="Comma separated TX VGA gains 1 and 2 (default: %s)" % default_txvga_gains_str, metavar="GAINS", type="string")
+ parser.add_option("-r", "--repeat", dest="repeat", help="Loop on input file indefinitely (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False)
+ parser.add_option("-I", "--stdin", dest="stdin", help="Input from stdin (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False)
+
+ (options, args) = parser.parse_args()
+
+ if options.ts_file == None:
+ options.ts_file = default_ts_file
+
+ if options.freq == None:
+ options.freq = int(default_freq)
+ else:
+ options.freq = int(options.freq)
+
+ if options.symbol_rate_str == None:
+ options.symbol_rate = 1000000
+ else:
+ options.symbol_rate = getInputFromDict(symbol_rates, options.symbol_rate_str)
+ if options.symbol_rate == None:
+ raise InputError("Invalid symbol rate specified")
+
+ if options.txvga_gains_str is None:
+ options.txvga_gains_str = default_txvga_gains_str
+
+ options.txvga_gains = []
+ for gain_str in options.txvga_gains_str.split(","):
+ options.txvga_gains.append(int(gain_str))
+
+ return options
+
+# ----------------------------------------------------------------------
+def getHalfBW(symbol_rate):
+# ----------------------------------------------------------------------
+ for half_bw in half_bws:
+ if symbol_rate / 2 <= half_bw:
+ return half_bw
+ return half_bws[:-1]
+
+# ======================================================================
+
+# ----------------------------------------------------------------------
+def main():
+# ----------------------------------------------------------------------
+ try:
+ options = getInputOptions()
+
+ ##################################################
+ # Variables
+ ##################################################
+
+ center_freq = options.freq
+ txvga1_gain = options.txvga_gains[0]
+ txvga2_gain = options.txvga_gains[1]
+
+ samp_rate = 2*options.symbol_rate
+ half_bw = getHalfBW(options.symbol_rate)
+
+ rrc_taps = 20
+
+ ##################################################
+ # Blocks
+ ##################################################
+
+ tb = gr.top_block()
+
+ if options.stdin:
+ blocks_file_source_0 = blocks.file_descriptor_source(gr.sizeof_char, 0, False)
+ else:
+ blocks_file_source_0 = blocks.file_source(gr.sizeof_char, options.ts_file, options.repeat)
+
+ fft_filter_xxx_0 = filter.fft_filter_ccc(1, (firdes.root_raised_cosine(1.79, samp_rate, samp_rate/2, 0.35, rrc_taps)), 1)
+ fft_filter_xxx_0.declare_sample_delay(0)
+ dvbs_reed_solomon_enc_bb_0 = dvbs.reed_solomon_enc_bb()
+ dvbs_randomizer_bb_0 = dvbs.randomizer_bb()
+ dvbs_puncture_bb_0 = dvbs.puncture_bb(dvbs.C1_2)
+ dvbs_modulator_bc_0 = dvbs.modulator_bc()
+ dvbs_interleaver_bb_0 = dvbs.interleaver_bb()
+ blocks_unpack_k_bits_bb_0 = blocks.unpack_k_bits_bb(2)
+ blocks_packed_to_unpacked_xx_0 = blocks.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST)
+ blocks_pack_k_bits_bb_0 = blocks.pack_k_bits_bb(2)
+ trellis_encoder_xx_0 = trellis.encoder_bb(trellis.fsm(1, 2, (0171, 0133)), 0, 0) if False else trellis.encoder_bb(trellis.fsm(1, 2, (0171, 0133)), 0)
+
+ osmosdr_sink_0 = osmosdr.sink( args="bladerf=0,buffers=128,buflen=32768," +"numchan=" + str(1))
+ osmosdr_sink_0.set_sample_rate(samp_rate)
+ osmosdr_sink_0.set_center_freq(center_freq, 0)
+ osmosdr_sink_0.set_freq_corr(0, 0)
+ osmosdr_sink_0.set_gain(txvga2_gain, 0)
+ osmosdr_sink_0.set_if_gain(0, 0)
+ osmosdr_sink_0.set_bb_gain(txvga1_gain, 0)
+ osmosdr_sink_0.set_antenna("", 0)
+ osmosdr_sink_0.set_bandwidth(half_bw * 2, 0)
+
+
+ ##################################################
+ # Connections
+ ##################################################
+
+ tb.connect((blocks_file_source_0, 0), (dvbs_randomizer_bb_0, 0))
+ tb.connect((blocks_pack_k_bits_bb_0, 0), (dvbs_modulator_bc_0, 0))
+ tb.connect((blocks_packed_to_unpacked_xx_0, 0), (trellis_encoder_xx_0, 0))
+ tb.connect((blocks_unpack_k_bits_bb_0, 0), (dvbs_puncture_bb_0, 0))
+ tb.connect((dvbs_interleaver_bb_0, 0), (blocks_packed_to_unpacked_xx_0, 0))
+ tb.connect((dvbs_modulator_bc_0, 0), (fft_filter_xxx_0, 0))
+ tb.connect((dvbs_puncture_bb_0, 0), (blocks_pack_k_bits_bb_0, 0))
+ tb.connect((dvbs_randomizer_bb_0, 0), (dvbs_reed_solomon_enc_bb_0, 0))
+ tb.connect((dvbs_reed_solomon_enc_bb_0, 0), (dvbs_interleaver_bb_0, 0))
+ tb.connect((fft_filter_xxx_0, 0), (osmosdr_sink_0, 0))
+ tb.connect((trellis_encoder_xx_0, 0), (blocks_unpack_k_bits_bb_0, 0))
+
+ if options.out_file:
+ dst = blocks.file_sink(gr.sizeof_gr_complex, options.out_file)
+ tb.connect(fft_filter_xxx_0, dst)
+
+ tb.run()
+
+ except KeyboardInterrupt:
+ pass
+
+# ----------------------------------------------------------------------
+if __name__ == "__main__":
+ main()
diff --git a/dvbt-tx.py b/dvbt-tx.py
index 6f9aea6..e5974bd 100755
--- a/dvbt-tx.py
+++ b/dvbt-tx.py
@@ -23,90 +23,201 @@
import dvbt
import osmosdr
import sys
+from optparse import OptionParser
-def main(args):
- nargs = len(args)
- if nargs == 1:
- infile = args[0]
- outfile = None
- elif nargs == 2:
- infile = args[0]
- outfile = args[1]
+# ======================================================================
+
+# ----------------------------------------------------------------------
+def getInputFromDict(input_dict, input_key):
+# ----------------------------------------------------------------------
+ if input_key in input_dict:
+ return input_dict[input_key]
+ else:
+ return None
+
+# ----------------------------------------------------------------------
+def getInputOptions():
+# ----------------------------------------------------------------------
+ default_ts_file = "/tmp/in.fifo"
+ default_freq = 437.5e6
+ default_width = 1e6
+ fft_sizes = {"2k": dvbt.T2k, "8k": dvbt.T8k}
+ code_rates = {"1/2": dvbt.C1_2, "2/3": dvbt.C2_3}
+ guard_intervals = {"1/4": dvbt.G1_4, "2/3": dvbt.G1_32}
+ constellations = {"QPSK": dvbt.QPSK, "QAM16": dvbt.QAM16, "QAM64": dvbt.QAM64}
+ default_txvga_gains_str = "-4,20"
+
+ parser = OptionParser(usage="usage: %%prog -r [-d [-f] [-q]] [-a] [-H]\n\n%s")
+ parser.add_option("-i", "--ts-file", dest="ts_file", help="Input transport stream file or FIFO (default %s)" % default_ts_file, metavar="DATA_FILE", type="string")
+ parser.add_option("-o", "--output-file", dest="out_file", help="Output complex samples file (default None)", metavar="OUTPUT_FILE", type="string")
+ parser.add_option("-f", "--frequency", dest="freq", help="Transmit center frequency in Hz (default %.3e)" % default_freq, metavar="FREQUENCY", type="float")
+ parser.add_option("-w", "--width", dest="width", help="Channel width in Hz (default %.3e)" % default_width, metavar="WIDTH", type="float")
+ parser.add_option("-F", "--fft-size", dest="fft_size_str", help="FFT size: %s (default 2k)" % fft_sizes.keys(), metavar="FFT_SIZE", type="string")
+ parser.add_option("-r", "--code-rate", dest="code_rate_str", help="FEC code rate: %s (default 1/2)" % code_rates.keys(), metavar="CODE_RATE", type="string")
+ parser.add_option("-g", "--guard-interval", dest="guard_interval_str", help="Guard interval: %s (default 1/4)" % guard_intervals.keys(), metavar="GUARD_INTERVAL", type="string")
+ parser.add_option("-c", "--constellation", dest="constellation_str", help="Constellations: %s (default QPSK)" % constellations.keys(), metavar="CONSTELLATION", type="string")
+ parser.add_option("-G", "--txvga-gains", dest="txvga_gains_str", help="Comma separated TX VGA gains 1 and 2 (default: %s)" % default_txvga_gains_str, metavar="GAINS", type="string")
+ parser.add_option("-R", "--repeat", dest="repeat", help="Loop on input file indefinitely (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False)
+ parser.add_option("-I", "--stdin", dest="stdin", help="Input from stdin (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False)
+
+ (options, args) = parser.parse_args()
+
+ options.fft_size = None
+ options.code_rate = None
+ options.guard_interval = None
+ options.constellation = None
+
+ if options.ts_file == None:
+ options.ts_file = default_ts_file
+
+ if options.freq == None:
+ options.freq = int(default_freq)
+ else:
+ options.freq = int(options.freq)
+
+ if options.width == None:
+ options.width = default_width
+
+ if options.fft_size_str == None:
+ options.fft_size = dvbt.T2k
else:
- sys.stderr.write("Usage: dvbt-blade.py input_file [output_file]\n");
- sys.exit(1)
-
- channel_mhz = 6
- mode = dvbt.T2k
- code_rate = dvbt.C1_2
- constellation = dvbt.QPSK
- symbol_rate = channel_mhz * 8000000.0 / 7
- center_freq = 441000000
- txvga1_gain = -4
- txvga2_gain = 25
-
- if mode == dvbt.T2k:
- factor = 1
- carriers = 2048
- elif mode == dvbt.T8k:
- factor = 4
- carriers = 8192
-
- if channel_mhz == 8:
- bandwidth = 8750000
- elif channel_mhz == 7:
- bandwidth = 7000000
- elif channel_mhz == 6:
- bandwidth = 6000000
- elif channel_mhz == 5:
- bandwidth = 5000000
+ options.fft_size = getInputFromDict(fft_sizes, options.fft_size_str)
+ if options.fft_size == None:
+ raise InputError("Invalid FFT size specified")
+
+ if options.code_rate_str == None:
+ options.code_rate = dvbt.C1_2
+ else:
+ options.code_rate = getInputFromDict(code_rates, options.code_rate_str)
+ if options.code_rate == None:
+ raise InputError("Invalid code rate specified")
+
+ if options.guard_interval_str == None:
+ options.guard_interval = dvbt.G1_4
+ else:
+ options.guard_interval = getInputFromDict(guard_intervals, options.guard_interval_str)
+ if options.code_rate == None:
+ raise InputError("Invalid guard interval specified")
+
+ if options.constellation_str == None:
+ options.constellation = dvbt.QPSK
else:
- bandwidth = 8750000
-
- tb = gr.top_block()
-
- src = blocks.file_source(gr.sizeof_char, infile, True)
-
- dvbt_energy_dispersal = dvbt.energy_dispersal(1 * factor)
- dvbt_reed_solomon_enc = dvbt.reed_solomon_enc(2, 8, 0x11d, 255, 239, 8, 51, (8 * factor))
- dvbt_convolutional_interleaver = dvbt.convolutional_interleaver((136 * factor), 12, 17)
- dvbt_inner_coder = dvbt.inner_coder(1, (1512 * factor), constellation, dvbt.NH, code_rate)
- dvbt_bit_inner_interleaver = dvbt.bit_inner_interleaver((1512 * factor), constellation, dvbt.NH, mode)
- dvbt_symbol_inner_interleaver = dvbt.symbol_inner_interleaver((1512 * factor), mode, 1)
- dvbt_dvbt_map = dvbt.dvbt_map((1512 * factor), constellation, dvbt.NH, mode, 1)
- dvbt_reference_signals = dvbt.reference_signals(gr.sizeof_gr_complex, (1512 * factor), carriers, constellation, dvbt.NH, code_rate, code_rate, dvbt.G1_32, mode, 0, 0)
- fft_vxx = fft.fft_vcc(carriers, False, (window.rectangular(carriers)), True, 10)
- digital_ofdm_cyclic_prefixer = digital.ofdm_cyclic_prefixer(carriers, carriers+(64 * factor), 0, "")
- blocks_multiply_const_vxx = blocks.multiply_const_vcc((0.0022097087 * 2.5, ))
-
- out = osmosdr.sink(args="bladerf=0,buffers=128,buflen=32768")
- out.set_sample_rate(symbol_rate)
- out.set_center_freq(center_freq, 0)
- out.set_freq_corr(0, 0)
- out.set_gain(txvga2_gain, 0)
- out.set_bb_gain(txvga1_gain, 0)
- out.set_bandwidth(bandwidth, 0)
-
- tb.connect(src, dvbt_energy_dispersal)
- tb.connect(dvbt_energy_dispersal, dvbt_reed_solomon_enc)
- tb.connect(dvbt_reed_solomon_enc, dvbt_convolutional_interleaver)
- tb.connect(dvbt_convolutional_interleaver, dvbt_inner_coder)
- tb.connect(dvbt_inner_coder, dvbt_bit_inner_interleaver)
- tb.connect(dvbt_bit_inner_interleaver, dvbt_symbol_inner_interleaver)
- tb.connect(dvbt_symbol_inner_interleaver, dvbt_dvbt_map)
- tb.connect(dvbt_dvbt_map, dvbt_reference_signals)
- tb.connect(dvbt_reference_signals, fft_vxx)
- tb.connect(fft_vxx, digital_ofdm_cyclic_prefixer)
- tb.connect(digital_ofdm_cyclic_prefixer, blocks_multiply_const_vxx)
- tb.connect(blocks_multiply_const_vxx, out)
-
-
- if outfile:
- dst = blocks.file_sink(gr.sizeof_gr_complex, outfile)
- tb.connect(blocks_multiply_const_vxx, dst)
-
- tb.run()
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])
+ options.constellation = getInputFromDict(constellations, options.constellation_str.upper())
+ if options.constellation == None:
+ raise InputError("Invalid constellation specified")
+
+ if options.txvga_gains_str is None:
+ options.txvga_gains_str = default_txvga_gains_str
+
+ options.txvga_gains = []
+ for gain_str in options.txvga_gains_str.split(","):
+ options.txvga_gains.append(int(gain_str))
+
+ return options
+
+# ======================================================================
+
+# ----------------------------------------------------------------------
+def main():
+# ----------------------------------------------------------------------
+ try:
+ options = getInputOptions()
+
+ ##################################################
+ # Variables
+ ##################################################
+
+ channel_mhz = options.width / 1e6
+ symbol_rate = channel_mhz * 8000000.0 / 7
+ center_freq = options.freq
+
+ mode = options.fft_size
+ code_rate = options.code_rate
+ guard = options.guard_interval
+ constellation = options.constellation
+
+ txvga1_gain = options.txvga_gains[0]
+ txvga2_gain = options.txvga_gains[1]
+
+ if mode == dvbt.T2k:
+ factor = 1
+ carriers = 2048
+ elif mode == dvbt.T8k:
+ factor = 4
+ carriers = 8192
+
+ if channel_mhz >= 8:
+ bandwidth = 8750000
+ elif channel_mhz <= 7:
+ bandwidth = 7000000
+ elif channel_mhz <= 6:
+ bandwidth = 6000000
+ elif channel_mhz <= 5:
+ bandwidth = 5000000
+ elif channel_mhz <= 2:
+ bandwidth = 2500000
+ elif channel_mhz <= 1:
+ bandwidth = 1500000
+ else:
+ bandwidth = 8750000
+
+ ##################################################
+ # Blocks
+ ##################################################
+
+ tb = gr.top_block()
+
+ if options.stdin:
+ src = blocks.file_descriptor_source(gr.sizeof_char, 0, False)
+ else:
+ src = blocks.file_source(gr.sizeof_char, options.ts_file, options.repeat)
+
+ dvbt_energy_dispersal = dvbt.energy_dispersal(1 * factor)
+ dvbt_reed_solomon_enc = dvbt.reed_solomon_enc(2, 8, 0x11d, 255, 239, 8, 51, (8 * factor))
+ dvbt_convolutional_interleaver = dvbt.convolutional_interleaver((136 * factor), 12, 17)
+ dvbt_inner_coder = dvbt.inner_coder(1, (1512 * factor), constellation, dvbt.NH, code_rate)
+ dvbt_bit_inner_interleaver = dvbt.bit_inner_interleaver((1512 * factor), constellation, dvbt.NH, mode)
+ dvbt_symbol_inner_interleaver = dvbt.symbol_inner_interleaver((1512 * factor), mode, 1)
+ dvbt_dvbt_map = dvbt.dvbt_map((1512 * factor), constellation, dvbt.NH, mode, 1)
+ dvbt_reference_signals = dvbt.reference_signals(gr.sizeof_gr_complex, (1512 * factor), carriers, constellation, dvbt.NH, code_rate, code_rate, guard, mode, 0, 0)
+ fft_vxx = fft.fft_vcc(carriers, False, (window.rectangular(carriers)), True, 10)
+ digital_ofdm_cyclic_prefixer = digital.ofdm_cyclic_prefixer(carriers, carriers+(64 * factor), 0, "")
+ blocks_multiply_const_vxx = blocks.multiply_const_vcc((0.0022097087 * 2.5, ))
+
+ out = osmosdr.sink(args="bladerf=0,buffers=128,buflen=32768")
+ out.set_sample_rate(symbol_rate)
+ out.set_center_freq(center_freq, 0)
+ out.set_freq_corr(0, 0)
+ out.set_gain(txvga2_gain, 0)
+ out.set_bb_gain(txvga1_gain, 0)
+ out.set_bandwidth(bandwidth, 0)
+
+ ##################################################
+ # Connections
+ ##################################################
+
+ tb.connect(src, dvbt_energy_dispersal)
+ tb.connect(dvbt_energy_dispersal, dvbt_reed_solomon_enc)
+ tb.connect(dvbt_reed_solomon_enc, dvbt_convolutional_interleaver)
+ tb.connect(dvbt_convolutional_interleaver, dvbt_inner_coder)
+ tb.connect(dvbt_inner_coder, dvbt_bit_inner_interleaver)
+ tb.connect(dvbt_bit_inner_interleaver, dvbt_symbol_inner_interleaver)
+ tb.connect(dvbt_symbol_inner_interleaver, dvbt_dvbt_map)
+ tb.connect(dvbt_dvbt_map, dvbt_reference_signals)
+ tb.connect(dvbt_reference_signals, fft_vxx)
+ tb.connect(fft_vxx, digital_ofdm_cyclic_prefixer)
+ tb.connect(digital_ofdm_cyclic_prefixer, blocks_multiply_const_vxx)
+ tb.connect(blocks_multiply_const_vxx, out)
+
+ if options.out_file:
+ dst = blocks.file_sink(gr.sizeof_gr_complex, options.out_file)
+ tb.connect(blocks_multiply_const_vxx, dst)
+
+ tb.run()
+
+ except KeyboardInterrupt:
+ pass
+
+# ----------------------------------------------------------------------
+if __name__ == "__main__":
+ main()