From 2b11e0f94a1ba6cb4e35e57155fe3838d906dcf1 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Tue, 2 May 2017 15:12:14 +0200 Subject: [PATCH] Retabbed python code and added secondary demodulators --- openwebrx.py | 6 +- plugins/dsp/csdr/plugin.py | 524 +++++++++++++++++++++++-------------- 2 files changed, 336 insertions(+), 194 deletions(-) mode change 100644 => 100755 plugins/dsp/csdr/plugin.py diff --git a/openwebrx.py b/openwebrx.py index 0e22076..b1b00d6 100755 --- a/openwebrx.py +++ b/openwebrx.py @@ -2,9 +2,9 @@ print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py """ - This file is part of OpenWebRX, - an open-source SDR receiver software with a web UI. - Copyright (c) 2013-2015 by Andras Retzler + This file is part of OpenWebRX, + an open-source SDR receiver software with a web UI. + Copyright (c) 2013-2015 by Andras Retzler This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as diff --git a/plugins/dsp/csdr/plugin.py b/plugins/dsp/csdr/plugin.py old mode 100644 new mode 100755 index b321471..cdd12b6 --- a/plugins/dsp/csdr/plugin.py +++ b/plugins/dsp/csdr/plugin.py @@ -1,9 +1,9 @@ """ OpenWebRX csdr plugin: do the signal processing with csdr - This file is part of OpenWebRX, - an open-source SDR receiver software with a web UI. - Copyright (c) 2013-2015 by Andras Retzler + This file is part of OpenWebRX, + an open-source SDR receiver software with a web UI. + Copyright (c) 2013-2015 by Andras Retzler This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -29,223 +29,365 @@ import fcntl class dsp_plugin: - def __init__(self): - self.samp_rate = 250000 - self.output_rate = 11025 #this is default, and cannot be set at the moment - self.fft_size = 1024 - self.fft_fps = 5 - self.offset_freq = 0 - self.low_cut = -4000 - self.high_cut = 4000 - self.bpf_transition_bw = 320 #Hz, and this is a constant - self.ddc_transition_bw_rate = 0.15 # of the IF sample rate - self.running = False - self.audio_compression = "none" - self.fft_compression = "none" - self.demodulator = "nfm" - self.name = "csdr" - self.format_conversion = "csdr convert_u8_f" - self.base_bufsize = 512 - self.nc_port = 4951 - self.csdr_dynamic_bufsize = False - self.csdr_print_bufsizes = False - self.csdr_through = False - self.squelch_level = 0 - self.fft_averages = 50 + def __init__(self): + self.samp_rate = 250000 + self.output_rate = 11025 #this is default, and cannot be set at the moment + self.fft_size = 1024 + self.fft_fps = 5 + self.offset_freq = 0 + self.low_cut = -4000 + self.high_cut = 4000 + self.bpf_transition_bw = 320 #Hz, and this is a constant + self.ddc_transition_bw_rate = 0.15 # of the IF sample rate + self.running = False + self.secondary_processes_running = False + self.audio_compression = "none" + self.fft_compression = "none" + self.demodulator = "nfm" + self.name = "csdr" + self.format_conversion = "csdr convert_u8_f" + self.base_bufsize = 512 + self.nc_port = 4951 + self.csdr_dynamic_bufsize = False + self.csdr_print_bufsizes = False + self.csdr_through = False + self.squelch_level = 0 + self.fft_averages = 50 + self.iqtee = False + self.iqtee2 = False + self.secondary_demodulator = None + self.secondary_fft_size = 1024 + self.secondary_process_fft = None + self.secondary_process_demod = None + self.pipe_names=["bpf_pipe", "shift_pipe", "squelch_pipe", "smeter_pipe", "iqtee_pipe", "iqtee2_pipe"] + self.secondary_pipe_names=["secondary_shift_pipe"] - def chain(self,which): - any_chain_base="nc -v 127.0.0.1 {nc_port} | " - if self.csdr_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | " - if self.csdr_through: any_chain_base+="csdr through | " - any_chain_base+=self.format_conversion+(" | " if self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | " - if which == "fft": - fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | " + \ - ("csdr logpower_cf -70 | " if self.fft_averages == 0 else "csdr logaveragepower_cf -70 {fft_size} {fft_averages} | ") + \ - "csdr fft_exchange_sides_ff {fft_size}" - if self.fft_compression=="adpcm": - return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}" - else: - return fft_chain_base - chain_begin=any_chain_base+"csdr shift_addition_cc --fifo {shift_pipe} | csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING | csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING | csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 1 | " - chain_end = "" - if self.audio_compression=="adpcm": - chain_end = " | csdr encode_ima_adpcm_i16_u8" - if which == "nfm": return chain_begin + "csdr fmdemod_quadri_cf | csdr limit_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr deemphasis_nfm_ff 11025 | csdr fastagc_ff 1024 | csdr convert_f_s16"+chain_end - elif which == "am": return chain_begin + "csdr amdemod_cf | csdr fastdcblock_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end - elif which == "ssb": return chain_begin + "csdr realpart_cf | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end + def chain(self,which): + any_chain_base="nc -v 127.0.0.1 {nc_port} | " + if self.csdr_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | " + if self.csdr_through: any_chain_base+="csdr through | " + any_chain_base+=self.format_conversion+(" | " if self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | " + if which == "fft": + fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | " + \ + ("csdr logpower_cf -70 | " if self.fft_averages == 0 else "csdr logaveragepower_cf -70 {fft_size} {fft_averages} | ") + \ + "csdr fft_exchange_sides_ff {fft_size}" + if self.fft_compression=="adpcm": + return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}" + else: + return fft_chain_base + chain_begin=any_chain_base+"csdr shift_addition_cc --fifo {shift_pipe} | csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING | csdr bandpass_fir_fft_cc --fifo {bpf_pipe} {bpf_transition_bw} HAMMING | csdr squelch_and_smeter_cc --fifo {squelch_pipe} --outfifo {smeter_pipe} 5 1 | " + if self.secondary_demodulator: + chain_begin+="tee {iqtee_pipe} | " + chain_begin+="tee {iqtee_pipe2} | " + chain_end = "" + if self.audio_compression=="adpcm": + chain_end = " | csdr encode_ima_adpcm_i16_u8" + if which == "nfm": return chain_begin + "csdr fmdemod_quadri_cf | csdr limit_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr deemphasis_nfm_ff 11025 | csdr fastagc_ff 1024 | csdr convert_f_s16"+chain_end + elif which == "am": return chain_begin + "csdr amdemod_cf | csdr fastdcblock_ff | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end + elif which == "ssb": return chain_begin + "csdr realpart_cf | csdr old_fractional_decimator_ff {last_decimation} | csdr agc_ff | csdr limit_ff | csdr convert_f_s16"+chain_end - def set_audio_compression(self,what): - self.audio_compression = what + def secondary_chain(self, which): + secondary_chain_base="cat {input_pipe} | " - def set_fft_compression(self,what): - self.fft_compression = what + if which == "fft": + return secondary_chain_base+"csdr fft_cc {secondary_fft_size} {secondary_fft_block_size} | csdrr logpower_cf -70 | csdr fft_one_side_ff {secondary_fft_size}" + elif which == "bpsk31": + return secondary_chain_base+"""csdr dsb_fc | \ +csdr shift_addition_cc {secondary_shift_pipe} | \ +csdr REM fir_decimate_cc {secondary_decimation} | \ +csdr bandpass_fir_fft_cc -{secondary_bpf_cutoff} {secondary_bpf_cutoff} {secondary_bpf_transition_bw} HAMMING | \ +csdr simple_agc_cc 0.0001 0.5 | \ +csdr matched_filter_cc COSINE 48 | \ +csdr timing_recovery_cc EARLYLATE {secondary_samples_per_bits} --add_q | \ - def get_fft_bytes_to_read(self): - if self.fft_compression=="none": return self.fft_size*4 - if self.fft_compression=="adpcm": return (self.fft_size/2)+(10/2) +CSDR_FIXED_BUFSIZE=1 csdr realpart_cf | \ +CSDR_FIXED_BUFSIZE=1 csdr binary_slicer_f_u8 | \ +CSDR_FIXED_BUFSIZE=1 csdr differential_decoder_u8_u8 | \ +CSDR_FIXED_BUFSIZE=1 csdr psk31_varicode_decoder_u8_u8 +""" - def set_samp_rate(self,samp_rate): - #to change this, restart is required - self.samp_rate=samp_rate - self.decimation=1 - while self.samp_rate/(self.decimation+1)>self.output_rate: - self.decimation+=1 - self.last_decimation=float(self.if_samp_rate())/self.output_rate + def set_secondary_demodulator(self, what): + self.secondary_demodulator = what - def if_samp_rate(self): - return self.samp_rate/self.decimation + def secondary_fft_block_size(self): + return (self.samp_rate/self.decimation)/self.fft_fps - def get_name(self): - return self.name + def secondary_decimation(self, which): + return 1 - def get_output_rate(self): - return self.output_rate + def secondary_bpf_cutoff(self, which): + if self.secondary_demodulator == "bpsk31": + return 31.25 / self.if_samp_rate() + return 0 - def set_output_rate(self,output_rate): - self.output_rate=output_rate - self.set_samp_rate(self.samp_rate) #as it depends on output_rate + def secondary_bpf_transition_bw(self, which): + if self.secondary_demodulator == "bpsk31": + return (31.25 / 2) * self.if_samp_rate() + return 0 - def set_demodulator(self,demodulator): - #to change this, restart is required - self.demodulator=demodulator + def start_secondary_demodulator(self): + if(not self.secondary_demodulator): return + secondary_command_fft=secondary_chain("fft") + secondary_command_fft=secondary_command_fft.format( \ + input_pipe=self.iqtee_pipe, \ + secondary_fft_size=self.secondary_fft_size, \ + secondary_fft_block_size=self.secondary_fft_block_size(), \ + ) + secondary_command_demod=self.secondary_chain(self.secondary_demodulator) + secondary_command_demod.format( \ + input_pipe=self.iqtee2_pipe, \ + secondary_shift_pipe=self.secondary_shift_pipe, \ + secondary_decimation=self.secondary_decimation(self.secondary_demodulator), \ + secondary_samples_per_bits=self.secondary_samples_per_bits(self.secondary_demodulator), \ + secondary_bpf_cutoff=self.secondary_bpf_cutoff(self.secondary_demodulator), \ + secondary_bpf_transition_bw=self.secondary_bpf_transition_bw(self.secondary_demodulator) + ) + try_create_pipes(secondary_command_demod + secondary_command_fft, self.secondary_pipe_names) - def get_demodulator(self): - return self.demodulator + print "[openwebrx-dsp-plugin:csdr] secondary command (fft) =", secondary_command_fft + print "[openwebrx-dsp-plugin:csdr] secondary command (demod) =", secondary_command_demod + #code.interact(local=locals()) + my_env=os.environ.copy() + #if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1"; + if self.csdr_print_bufsizes: my_env["CSDR_PRINT_BUFSIZES"]="1"; + self.secondary_process_fft = subprocess.Popen(secondary_command_fft, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env) + self.secondary_process_demod = subprocess.Popen(secondary_command_demod, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env) + self.secondary_processes_running = True - def set_fft_size(self,fft_size): - #to change this, restart is required - self.fft_size=fft_size + #open control pipes for csdr and send initialization data + if self.secondary_shift_pipe != None: + self.secondary_shift_pipe_file=open(self.secondary_shift_pipe,"w") + self.set_secondary_offset_freq(self.secondary_offset_freq) - def set_fft_fps(self,fft_fps): - #to change this, restart is required - self.fft_fps=fft_fps + def set_secondary_offset_freq(self, value): + self.secondary_offset_freq=value + if self.secondary_processes_running: + self.secondary_shift_pipe_file.write("%g\n"%(-float(self.secondary_offset_freq)/self.if_samp_rate())) + self.secondary_shift_pipe_file.flush() - def set_fft_averages(self,fft_averages): - #to change this, restart is required - self.fft_averages=fft_averages + def stop_secondary_demodulator(self): + if self.secondary_processes_running == False: return + self.try_delete_pipes(self.secondary_pipe_names) + if self.secondary_process_fft: os.killpg(os.getpgid(self.secondary_process_fft.pid), signal.SIGTERM) + if self.secondary_process_demod: os.killpg(os.getpgid(self.secondary_process_demod.pid), signal.SIGTERM) + self.secondary_processes_running = False - def fft_block_size(self): - if self.fft_averages == 0: return self.samp_rate/self.fft_fps - else: return self.samp_rate/self.fft_fps/self.fft_averages + def read_secondary_demod(self, size): + return self.secondary_process_demod.stdout.read(size) - def set_format_conversion(self,format_conversion): - self.format_conversion=format_conversion + def read_secondary_fft(self, size): + return self.secondary_process_fft.stdout.read(size) - def set_offset_freq(self,offset_freq): - self.offset_freq=offset_freq - if self.running: - self.shift_pipe_file.write("%g\n"%(-float(self.offset_freq)/self.samp_rate)) - self.shift_pipe_file.flush() + def set_audio_compression(self,what): + self.audio_compression = what - def set_bpf(self,low_cut,high_cut): - self.low_cut=low_cut - self.high_cut=high_cut - if self.running: - self.bpf_pipe_file.write( "%g %g\n"%(float(self.low_cut)/self.if_samp_rate(), float(self.high_cut)/self.if_samp_rate()) ) - self.bpf_pipe_file.flush() + def set_fft_compression(self,what): + self.fft_compression = what - def get_bpf(self): - return [self.low_cut, self.high_cut] + def get_fft_bytes_to_read(self): + if self.fft_compression=="none": return self.fft_size*4 + if self.fft_compression=="adpcm": return (self.fft_size/2)+(10/2) - def set_squelch_level(self, squelch_level): - self.squelch_level=squelch_level - if self.running: - self.squelch_pipe_file.write( "%g\n"%(float(self.squelch_level)) ) - self.squelch_pipe_file.flush() + def set_samp_rate(self,samp_rate): + #to change this, restart is required + self.samp_rate=samp_rate + self.decimation=1 + while self.samp_rate/(self.decimation+1)>self.output_rate: + self.decimation+=1 + self.last_decimation=float(self.if_samp_rate())/self.output_rate - def get_smeter_level(self): - if self.running: - line=self.smeter_pipe_file.readline() - return float(line[:-1]) + def if_samp_rate(self): + return self.samp_rate/self.decimation - def mkfifo(self,path): - try: - os.unlink(path) - except: - pass - os.mkfifo(path) + def get_name(self): + return self.name - def ddc_transition_bw(self): - return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate)) + def get_output_rate(self): + return self.output_rate - def start(self): - command_base=self.chain(self.demodulator) + def set_output_rate(self,output_rate): + self.output_rate=output_rate + self.set_samp_rate(self.samp_rate) #as it depends on output_rate - #create control pipes for csdr - pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self)) - self.bpf_pipe = self.shift_pipe = self.squelch_pipe = self.smeter_pipe = None - if "{bpf_pipe}" in command_base: - self.bpf_pipe=pipe_base_path+"bpf" - self.mkfifo(self.bpf_pipe) - if "{shift_pipe}" in command_base: - self.shift_pipe=pipe_base_path+"shift" - self.mkfifo(self.shift_pipe) - if "{squelch_pipe}" in command_base: - self.squelch_pipe=pipe_base_path+"squelch" - self.mkfifo(self.squelch_pipe) - if "{smeter_pipe}" in command_base: - self.smeter_pipe=pipe_base_path+"smeter" - self.mkfifo(self.smeter_pipe) + def set_demodulator(self,demodulator): + #to change this, restart is required + self.demodulator=demodulator - #run the command - command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \ - last_decimation=self.last_decimation, fft_size=self.fft_size, fft_block_size=self.fft_block_size(), fft_averages=self.fft_averages, \ - 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, \ - squelch_pipe=self.squelch_pipe, smeter_pipe=self.smeter_pipe ) + def get_demodulator(self): + return self.demodulator - print "[openwebrx-dsp-plugin:csdr] Command =",command - #code.interact(local=locals()) - my_env=os.environ.copy() - if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1"; - if self.csdr_print_bufsizes: my_env["CSDR_PRINT_BUFSIZES"]="1"; - self.process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env) - self.running = True + def set_fft_size(self,fft_size): + #to change this, restart is required + self.fft_size=fft_size - #open control pipes for csdr and send initialization data - if self.bpf_pipe != None: - self.bpf_pipe_file=open(self.bpf_pipe,"w") - self.set_bpf(self.low_cut,self.high_cut) - if self.shift_pipe != None: - self.shift_pipe_file=open(self.shift_pipe,"w") - self.set_offset_freq(self.offset_freq) - if self.squelch_pipe != None: - self.squelch_pipe_file=open(self.squelch_pipe,"w") - self.set_squelch_level(self.squelch_level) - if self.smeter_pipe != None: - self.smeter_pipe_file=open(self.smeter_pipe,"r") - fcntl.fcntl(self.smeter_pipe_file, fcntl.F_SETFL, os.O_NONBLOCK) + def set_fft_fps(self,fft_fps): + #to change this, restart is required + self.fft_fps=fft_fps - def read(self,size): - return self.process.stdout.read(size) + def set_fft_averages(self,fft_averages): + #to change this, restart is required + self.fft_averages=fft_averages - def stop(self): - os.killpg(os.getpgid(self.process.pid), signal.SIGTERM) - #if(self.process.poll()!=None):return # returns None while subprocess is running - #while(self.process.poll()==None): - # #self.process.kill() - # print "killproc",os.getpgid(self.process.pid),self.process.pid - # os.killpg(self.process.pid, signal.SIGTERM) - # - # time.sleep(0.1) - if self.bpf_pipe: - try: os.unlink(self.bpf_pipe) - except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe - if self.shift_pipe: - try: os.unlink(self.shift_pipe) - except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.shift_pipe - if self.squelch_pipe: - try: os.unlink(self.squelch_pipe) - except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.squelch_pipe - if self.smeter_pipe: - try: os.unlink(self.smeter_pipe) - except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.smeter_pipe - self.running = False + def fft_block_size(self): + if self.fft_averages == 0: return self.samp_rate/self.fft_fps + else: return self.samp_rate/self.fft_fps/self.fft_averages - def restart(self): - self.stop() - self.start() + def set_format_conversion(self,format_conversion): + self.format_conversion=format_conversion - def __del__(self): - self.stop() - del(self.process) + def set_offset_freq(self,offset_freq): + self.offset_freq=offset_freq + if self.running: + self.shift_pipe_file.write("%g\n"%(-float(self.offset_freq)/self.samp_rate)) + self.shift_pipe_file.flush() + + def set_bpf(self,low_cut,high_cut): + self.low_cut=low_cut + self.high_cut=high_cut + if self.running: + self.bpf_pipe_file.write( "%g %g\n"%(float(self.low_cut)/self.if_samp_rate(), float(self.high_cut)/self.if_samp_rate()) ) + self.bpf_pipe_file.flush() + + def get_bpf(self): + return [self.low_cut, self.high_cut] + + def set_squelch_level(self, squelch_level): + self.squelch_level=squelch_level + if self.running: + self.squelch_pipe_file.write( "%g\n"%(float(self.squelch_level)) ) + self.squelch_pipe_file.flush() + + def get_smeter_level(self): + if self.running: + line=self.smeter_pipe_file.readline() + return float(line[:-1]) + + def mkfifo(self,path): + try: + os.unlink(path) + except: + pass + os.mkfifo(path) + + def ddc_transition_bw(self): + return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate)) + + def try_create_pipes(self, pipe_names, command_base): + for pipe_name in pipe_names: + if "{"+pipe_name+"}" in command_base: + setattr(self, pipe_name, self.pipe_base_path+pipe_name) + self.mkfifo(getattr(self, pipe_name)) + else: + setattr(self, pipe_name, None) + + def try_delete_pipes(self, pipe_names): + for pipe_name in pipe_names: + pipe_path = getattr(self,pipe_name,None) + if pipe_path: + try: os.unlink(pipe_path) + except: print "[openwebrx-dsp-plugin:csdr] try_delete_pipes() :: unlink failed: " + pipe_path + + + def start(self): + command_base=self.chain(self.demodulator) + + #create control pipes for csdr + self.pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self)) + # self.bpf_pipe = self.shift_pipe = self.squelch_pipe = self.smeter_pipe = None + + self.try_create_pipes(self.pipe_names, command_base) + + # if "{bpf_pipe}" in command_base: + # self.bpf_pipe=pipe_base_path+"bpf" + # self.mkfifo(self.bpf_pipe) + # if "{shift_pipe}" in command_base: + # self.shift_pipe=pipe_base_path+"shift" + # self.mkfifo(self.shift_pipe) + # if "{squelch_pipe}" in command_base: + # self.squelch_pipe=pipe_base_path+"squelch" + # self.mkfifo(self.squelch_pipe) + # if "{smeter_pipe}" in command_base: + # self.smeter_pipe=pipe_base_path+"smeter" + # self.mkfifo(self.smeter_pipe) + # if "{iqtee_pipe}" in command_base: + # self.iqtee_pipe=pipe_base_path+"iqtee" + # self.mkfifo(self.iqtee_pipe) + # if "{iqtee2_pipe}" in command_base: + # self.iqtee2_pipe=pipe_base_path+"iqtee2" + # self.mkfifo(self.iqtee2_pipe) + + #run the command + command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \ + last_decimation=self.last_decimation, fft_size=self.fft_size, fft_block_size=self.fft_block_size(), fft_averages=self.fft_averages, \ + 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, \ + squelch_pipe=self.squelch_pipe, smeter_pipe=self.smeter_pipe ) + + print "[openwebrx-dsp-plugin:csdr] Command =",command + #code.interact(local=locals()) + my_env=os.environ.copy() + if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1"; + if self.csdr_print_bufsizes: my_env["CSDR_PRINT_BUFSIZES"]="1"; + self.process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env) + self.running = True + + #open control pipes for csdr and send initialization data + if self.bpf_pipe != None: + self.bpf_pipe_file=open(self.bpf_pipe,"w") + self.set_bpf(self.low_cut,self.high_cut) + if self.shift_pipe != None: + self.shift_pipe_file=open(self.shift_pipe,"w") + self.set_offset_freq(self.offset_freq) + if self.squelch_pipe != None: + self.squelch_pipe_file=open(self.squelch_pipe,"w") + self.set_squelch_level(self.squelch_level) + if self.smeter_pipe != None: + self.smeter_pipe_file=open(self.smeter_pipe,"r") + fcntl.fcntl(self.smeter_pipe_file, fcntl.F_SETFL, os.O_NONBLOCK) + + self.start_secondary_demodulator() + + def read(self,size): + return self.process.stdout.read(size) + + def stop(self): + os.killpg(os.getpgid(self.process.pid), signal.SIGTERM) + self.stop_secondary_demodulator() + #if(self.process.poll()!=None):return # returns None while subprocess is running + #while(self.process.poll()==None): + # #self.process.kill() + # print "killproc",os.getpgid(self.process.pid),self.process.pid + # os.killpg(self.process.pid, signal.SIGTERM) + # + # time.sleep(0.1) + + self.try_delete_pipes(self.pipe_names) + + # if self.bpf_pipe: + # try: os.unlink(self.bpf_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.bpf_pipe + # if self.shift_pipe: + # try: os.unlink(self.shift_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.shift_pipe + # if self.squelch_pipe: + # try: os.unlink(self.squelch_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.squelch_pipe + # if self.smeter_pipe: + # try: os.unlink(self.smeter_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.smeter_pipe + # if self.iqtee_pipe: + # try: os.unlink(self.iqtee_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.iqtee_pipe + # if self.iqtee2_pipe: + # try: os.unlink(self.iqtee2_pipe) + # except: print "[openwebrx-dsp-plugin:csdr] stop() :: unlink failed: " + self.iqtee2_pipe + + self.running = False + + def restart(self): + self.stop() + self.start() + + def __del__(self): + self.stop() + del(self.process)