|
|
|
@ -59,7 +59,6 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
self.fft_compression = "none"
|
|
|
|
|
self.demodulator = "nfm"
|
|
|
|
|
self.name = "csdr"
|
|
|
|
|
self.base_bufsize = 512
|
|
|
|
|
self.decimation = None
|
|
|
|
|
self.last_decimation = None
|
|
|
|
|
self.nc_port = None
|
|
|
|
@ -109,23 +108,24 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
chain = ["nc -v 127.0.0.1 {nc_port}"]
|
|
|
|
|
if which == "fft":
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr fft_cc {fft_size} {fft_block_size}",
|
|
|
|
|
"csdr logpower_cf -70"
|
|
|
|
|
"csdr++ fft {fft_size} {fft_block_size}",
|
|
|
|
|
"csdr++ logpower -70"
|
|
|
|
|
if self.fft_averages == 0
|
|
|
|
|
else "csdr logaveragepower_cf -70 {fft_size} {fft_averages}",
|
|
|
|
|
"csdr fft_exchange_sides_ff {fft_size}",
|
|
|
|
|
else "csdr++ logaveragepower {fft_size} {fft_averages} --add -70",
|
|
|
|
|
"csdr++ fftswap {fft_size}",
|
|
|
|
|
]
|
|
|
|
|
if self.fft_compression == "adpcm":
|
|
|
|
|
chain += ["csdr compress_fft_adpcm_f_u8 {fft_size}"]
|
|
|
|
|
chain += ["csdr++ fftadpcm {fft_size}"]
|
|
|
|
|
return chain
|
|
|
|
|
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
|
|
|
|
|
chain += ["csdr++ shift --fifo {shift_pipe}"]
|
|
|
|
|
if self.decimation > 1:
|
|
|
|
|
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
|
|
|
|
chain += ["csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING"]
|
|
|
|
|
chain += ["csdr++ firdecimate {decimation} {ddc_transition_bw} --window hamming"]
|
|
|
|
|
chain += ["csdr++ bandpass --fft --fifo {bpf_pipe} {bpf_transition_bw} --window hamming"]
|
|
|
|
|
if self.output.supports_type("smeter"):
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 {smeter_report_every}"
|
|
|
|
|
]
|
|
|
|
|
if self.isSquelchActive():
|
|
|
|
|
chain += ["csdr++ squelch --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 {smeter_report_every}"]
|
|
|
|
|
else:
|
|
|
|
|
chain += ["csdr++ power --outfifo {smeter_pipe} 5 {smeter_report_every}"]
|
|
|
|
|
if self.secondary_demodulator:
|
|
|
|
|
if self.output.supports_type("secondary_fft"):
|
|
|
|
|
chain += ["csdr tee {iqtee_pipe}"]
|
|
|
|
@ -137,38 +137,38 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
last_decimation_block = []
|
|
|
|
|
if self.last_decimation >= 2.0:
|
|
|
|
|
# activate prefilter if signal has been oversampled, e.g. WFM
|
|
|
|
|
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation} 12 --prefilter"]
|
|
|
|
|
last_decimation_block = ["csdr++ fractionaldecimator --format float {last_decimation} --prefilter"]
|
|
|
|
|
elif self.last_decimation != 1.0:
|
|
|
|
|
last_decimation_block = ["csdr fractional_decimator_ff {last_decimation}"]
|
|
|
|
|
last_decimation_block = ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
|
|
|
|
if which == "nfm":
|
|
|
|
|
chain += ["csdr fmdemod_quadri_cf", "csdr limit_ff"]
|
|
|
|
|
chain += ["csdr++ fmdemod", "csdr++ limit"]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr deemphasis_nfm_ff {audio_rate}",
|
|
|
|
|
"csdr agc_ff --profile slow --max 3",
|
|
|
|
|
"csdr++ deemphasis --nfm {audio_rate}",
|
|
|
|
|
"csdr++ agc --format float --profile slow --max 3",
|
|
|
|
|
]
|
|
|
|
|
if self.get_audio_rate() != self.get_output_rate():
|
|
|
|
|
chain += [
|
|
|
|
|
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
|
|
|
|
]
|
|
|
|
|
else:
|
|
|
|
|
chain += ["csdr convert_f_s16"]
|
|
|
|
|
chain += ["csdr++ convert -i float -o s16"]
|
|
|
|
|
elif which == "wfm":
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr fmdemod_quadri_cf",
|
|
|
|
|
"csdr limit_ff",
|
|
|
|
|
"csdr++ fmdemod",
|
|
|
|
|
"csdr++ limit",
|
|
|
|
|
]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += ["csdr deemphasis_wfm_ff {audio_rate} {wfm_deemphasis_tau}", "csdr convert_f_s16"]
|
|
|
|
|
chain += ["csdr++ deemphasis --wfm {audio_rate} {wfm_deemphasis_tau}", "csdr++ convert -i float -o s16"]
|
|
|
|
|
elif self.isDigitalVoice(which):
|
|
|
|
|
chain += ["csdr fmdemod_quadri_cf"]
|
|
|
|
|
chain += ["csdr++ fmdemod"]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += ["dc_block"]
|
|
|
|
|
# m17
|
|
|
|
|
if which == "m17":
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr limit_ff",
|
|
|
|
|
"csdr convert_f_s16",
|
|
|
|
|
"csdr++ limit",
|
|
|
|
|
"csdr++ convert -i float -o s16",
|
|
|
|
|
"m17-demod",
|
|
|
|
|
]
|
|
|
|
|
else:
|
|
|
|
@ -197,87 +197,87 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y {codecserver_arg}"]
|
|
|
|
|
chain += ["digitalvoice_filter"]
|
|
|
|
|
chain += [
|
|
|
|
|
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
|
|
|
|
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
|
|
|
|
"csdr++ agc --format s16 --max 30 --initial 3",
|
|
|
|
|
"sox --buffer 320 -t raw -r 8000 -e signed-integer -b 16 -c 1 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
|
|
|
|
]
|
|
|
|
|
elif which == "am":
|
|
|
|
|
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
|
|
|
|
chain += ["csdr++ amdemod", "csdr++ dcblock"]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr agc_ff --profile slow --initial 200",
|
|
|
|
|
"csdr convert_f_s16",
|
|
|
|
|
"csdr++ agc --format float --profile slow --initial 200",
|
|
|
|
|
"csdr++ convert -i float -o s16",
|
|
|
|
|
]
|
|
|
|
|
elif self.isFreeDV(which):
|
|
|
|
|
chain += ["csdr realpart_cf"]
|
|
|
|
|
chain += ["csdr++ realpart"]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr agc_ff",
|
|
|
|
|
"csdr convert_f_s16",
|
|
|
|
|
"csdr++ agc --format float",
|
|
|
|
|
"csdr++ convert -i float -o s16",
|
|
|
|
|
"freedv_rx 1600 - -",
|
|
|
|
|
"csdr agc_s16 --max 30 --initial 3",
|
|
|
|
|
"csdr++ agc --format s16 --max 30 --initial 3",
|
|
|
|
|
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
|
|
|
|
]
|
|
|
|
|
elif self.isDrm(which):
|
|
|
|
|
if self.last_decimation != 1.0:
|
|
|
|
|
# we are still dealing with complex samples here, so the regular last_decimation_block doesn't fit
|
|
|
|
|
chain += ["csdr fractional_decimator_cc {last_decimation}"]
|
|
|
|
|
chain += ["csdr++ fractionaldecimator --format complex {last_decimation}"]
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr convert_f_s16",
|
|
|
|
|
"csdr++ convert -i float -o s16",
|
|
|
|
|
"dream -c 6 --sigsrate 48000 --audsrate 48000 -I - -O -",
|
|
|
|
|
"sox -t raw -r 48000 -e signed-integer -b 16 -c 2 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
|
|
|
|
]
|
|
|
|
|
elif which == "ssb":
|
|
|
|
|
chain += ["csdr realpart_cf"]
|
|
|
|
|
chain += ["csdr++ realpart"]
|
|
|
|
|
chain += last_decimation_block
|
|
|
|
|
chain += ["csdr agc_ff"]
|
|
|
|
|
chain += ["csdr++ agc --format float"]
|
|
|
|
|
# fixed sample rate necessary for the wsjt-x tools. fix with sox...
|
|
|
|
|
if self.get_audio_rate() != self.get_output_rate():
|
|
|
|
|
chain += [
|
|
|
|
|
"sox -t raw -r {audio_rate} -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - "
|
|
|
|
|
]
|
|
|
|
|
else:
|
|
|
|
|
chain += ["csdr convert_f_s16"]
|
|
|
|
|
chain += ["csdr++ convert -i float -o s16"]
|
|
|
|
|
|
|
|
|
|
if self.audio_compression == "adpcm":
|
|
|
|
|
chain += ["csdr encode_ima_adpcm_i16_u8"]
|
|
|
|
|
chain += ["csdr++ adpcm -e --sync"]
|
|
|
|
|
return chain
|
|
|
|
|
|
|
|
|
|
def secondary_chain(self, which):
|
|
|
|
|
chain = ["cat {input_pipe}"]
|
|
|
|
|
if which == "fft":
|
|
|
|
|
chain += [
|
|
|
|
|
"csdr fft_cc {secondary_fft_input_size} {secondary_fft_block_size}",
|
|
|
|
|
"csdr logpower_cf -70"
|
|
|
|
|
"csdr++ fft {secondary_fft_input_size} {secondary_fft_block_size}",
|
|
|
|
|
"csdr++ logpower -70"
|
|
|
|
|
if self.fft_averages == 0
|
|
|
|
|
else "csdr logaveragepower_cf -70 {secondary_fft_size} {fft_averages}",
|
|
|
|
|
"csdr fft_exchange_sides_ff {secondary_fft_input_size}",
|
|
|
|
|
else "csdr++ logaveragepower {secondary_fft_size} {fft_averages} --add -70",
|
|
|
|
|
"csdr++ fftswap {secondary_fft_input_size}",
|
|
|
|
|
]
|
|
|
|
|
if self.fft_compression == "adpcm":
|
|
|
|
|
chain += ["csdr compress_fft_adpcm_f_u8 {secondary_fft_size}"]
|
|
|
|
|
chain += ["csdr++ fftadpcm {secondary_fft_size}"]
|
|
|
|
|
return chain
|
|
|
|
|
elif which == "bpsk31" or which == "bpsk63":
|
|
|
|
|
return chain + [
|
|
|
|
|
"csdr shift_addfast_cc --fifo {secondary_shift_pipe}",
|
|
|
|
|
"csdr bandpass_fir_fft_cc -{secondary_bpf_cutoff} {secondary_bpf_cutoff} {secondary_bpf_cutoff}",
|
|
|
|
|
"csdr simple_agc_cc 0.001 0.5",
|
|
|
|
|
"csdr timing_recovery_cc GARDNER {secondary_samples_per_bits} 0.5 2 --add_q",
|
|
|
|
|
"CSDR_FIXED_BUFSIZE=1 csdr dbpsk_decoder_c_u8",
|
|
|
|
|
"CSDR_FIXED_BUFSIZE=1 csdr psk31_varicode_decoder_u8_u8",
|
|
|
|
|
"csdr++ shift --fifo {secondary_shift_pipe}",
|
|
|
|
|
"csdr++ bandpass --low -{secondary_bpf_cutoff} --high {secondary_bpf_cutoff} {secondary_bpf_cutoff}",
|
|
|
|
|
"csdr++ agc --format complex",
|
|
|
|
|
"csdr++ timingrecovery --algorithm gardner {secondary_samples_per_bits} 0.5 2 --add_q",
|
|
|
|
|
"csdr++ dbpskdecode",
|
|
|
|
|
"csdr++ varicodedecode",
|
|
|
|
|
]
|
|
|
|
|
elif self.isWsjtMode(which) or self.isJs8(which):
|
|
|
|
|
chain += ["csdr realpart_cf"]
|
|
|
|
|
chain += ["csdr++ realpart"]
|
|
|
|
|
if self.last_decimation != 1.0:
|
|
|
|
|
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
|
|
|
|
return chain + ["csdr agc_ff", "csdr convert_f_s16"]
|
|
|
|
|
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
|
|
|
|
return chain + ["csdr++ agc --format float", "csdr++ convert -i float -o s16"]
|
|
|
|
|
elif which == "packet":
|
|
|
|
|
chain += ["csdr fmdemod_quadri_cf"]
|
|
|
|
|
chain += ["csdr++ fmdemod"]
|
|
|
|
|
if self.last_decimation != 1.0:
|
|
|
|
|
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
|
|
|
|
return chain + ["csdr convert_f_s16", "direwolf -c {direwolf_config} -r {audio_rate} -t 0 -q d -q h 1>&2"]
|
|
|
|
|
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
|
|
|
|
return chain + ["csdr++ convert -i float -o s16", "direwolf -c {direwolf_config} -r {audio_rate} -t 0 -q d -q h 1>&2"]
|
|
|
|
|
elif which == "pocsag":
|
|
|
|
|
chain += ["csdr fmdemod_quadri_cf"]
|
|
|
|
|
chain += ["csdr++ fmdemod"]
|
|
|
|
|
if self.last_decimation != 1.0:
|
|
|
|
|
chain += ["csdr fractional_decimator_ff {last_decimation}"]
|
|
|
|
|
chain += ["csdr++ fractionaldecimator --format float {last_decimation}"]
|
|
|
|
|
return chain + ["fsk_demodulator -i", "pocsag_decoder"]
|
|
|
|
|
|
|
|
|
|
def set_secondary_demodulator(self, what):
|
|
|
|
@ -290,8 +290,8 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
def secondary_fft_block_size(self):
|
|
|
|
|
base = (self.samp_rate / self.decimation) / (self.fft_fps * 2)
|
|
|
|
|
if self.fft_averages == 0:
|
|
|
|
|
return base
|
|
|
|
|
return base / self.fft_averages
|
|
|
|
|
return round(base)
|
|
|
|
|
return round(base / self.fft_averages)
|
|
|
|
|
|
|
|
|
|
def secondary_decimation(self):
|
|
|
|
|
return 1 # currently unused
|
|
|
|
@ -594,9 +594,9 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
|
|
|
|
|
def fft_block_size(self):
|
|
|
|
|
if self.fft_averages == 0:
|
|
|
|
|
return self.samp_rate / self.fft_fps
|
|
|
|
|
return round(self.samp_rate / self.fft_fps)
|
|
|
|
|
else:
|
|
|
|
|
return self.samp_rate / self.fft_fps / self.fft_averages
|
|
|
|
|
return round(self.samp_rate / self.fft_fps / self.fft_averages)
|
|
|
|
|
|
|
|
|
|
def set_offset_freq(self, offset_freq):
|
|
|
|
|
if offset_freq is None:
|
|
|
|
@ -629,15 +629,14 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
def convertToLinear(self, db):
|
|
|
|
|
return float(math.pow(10, db / 10))
|
|
|
|
|
|
|
|
|
|
def isSquelchActive(self):
|
|
|
|
|
return not self.isDigitalVoice() and not self.isPacket() and not self.isPocsag() and not self.isFreeDV() and not self.isDrm()
|
|
|
|
|
|
|
|
|
|
def set_squelch_level(self, squelch_level):
|
|
|
|
|
self.squelch_level = squelch_level
|
|
|
|
|
# no squelch required on digital voice modes
|
|
|
|
|
actual_squelch = (
|
|
|
|
|
-150
|
|
|
|
|
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV() or self.isDrm()
|
|
|
|
|
else self.squelch_level
|
|
|
|
|
)
|
|
|
|
|
if self.running:
|
|
|
|
|
actual_squelch = self.squelch_level if self.isSquelchActive() else -150
|
|
|
|
|
if self.running and "squelch_pipe" in self.pipes:
|
|
|
|
|
self.pipes["squelch_pipe"].write("%g\n" % (self.convertToLinear(actual_squelch)))
|
|
|
|
|
|
|
|
|
|
def set_codecserver(self, s):
|
|
|
|
@ -757,7 +756,6 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
bpf_transition_bw=float(self.bpf_transition_bw) / self.if_samp_rate(),
|
|
|
|
|
ddc_transition_bw=self.ddc_transition_bw(),
|
|
|
|
|
flowcontrol=int(self.samp_rate * 2),
|
|
|
|
|
start_bufsize=self.base_bufsize * self.decimation,
|
|
|
|
|
nc_port=self.nc_port,
|
|
|
|
|
output_rate=self.get_output_rate(),
|
|
|
|
|
smeter_report_every=int(self.if_samp_rate() / 6000),
|
|
|
|
@ -769,7 +767,7 @@ class Dsp(DirewolfConfigSubscriber):
|
|
|
|
|
logger.debug("Command = %s", command)
|
|
|
|
|
|
|
|
|
|
out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL
|
|
|
|
|
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True)
|
|
|
|
|
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True, bufsize=128)
|
|
|
|
|
|
|
|
|
|
def watch_thread():
|
|
|
|
|
rc = self.process.wait()
|
|
|
|
|