Retabbed python code and added secondary demodulators
This commit is contained in:
		@@ -2,9 +2,9 @@
 | 
				
			|||||||
print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py
 | 
					print "" # python2.7 is required to run OpenWebRX instead of python3. Please run me by: python2 openwebrx.py
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	This file is part of OpenWebRX,
 | 
					    This file is part of OpenWebRX,
 | 
				
			||||||
	an open-source SDR receiver software with a web UI.
 | 
					    an open-source SDR receiver software with a web UI.
 | 
				
			||||||
	Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
 | 
					    Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    This program is free software: you can redistribute it and/or modify
 | 
					    This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
    it under the terms of the GNU Affero General Public License as
 | 
					    it under the terms of the GNU Affero General Public License as
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										524
									
								
								plugins/dsp/csdr/plugin.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										524
									
								
								plugins/dsp/csdr/plugin.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -1,9 +1,9 @@
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
OpenWebRX csdr plugin: do the signal processing with csdr
 | 
					OpenWebRX csdr plugin: do the signal processing with csdr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	This file is part of OpenWebRX,
 | 
					    This file is part of OpenWebRX,
 | 
				
			||||||
	an open-source SDR receiver software with a web UI.
 | 
					    an open-source SDR receiver software with a web UI.
 | 
				
			||||||
	Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
 | 
					    Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    This program is free software: you can redistribute it and/or modify
 | 
					    This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
    it under the terms of the GNU Affero General Public License as
 | 
					    it under the terms of the GNU Affero General Public License as
 | 
				
			||||||
@@ -29,223 +29,365 @@ import fcntl
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class dsp_plugin:
 | 
					class dsp_plugin:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
		self.samp_rate = 250000
 | 
					        self.samp_rate = 250000
 | 
				
			||||||
		self.output_rate = 11025 #this is default, and cannot be set at the moment
 | 
					        self.output_rate = 11025 #this is default, and cannot be set at the moment
 | 
				
			||||||
		self.fft_size = 1024
 | 
					        self.fft_size = 1024
 | 
				
			||||||
		self.fft_fps = 5
 | 
					        self.fft_fps = 5
 | 
				
			||||||
		self.offset_freq = 0
 | 
					        self.offset_freq = 0
 | 
				
			||||||
		self.low_cut = -4000
 | 
					        self.low_cut = -4000
 | 
				
			||||||
		self.high_cut = 4000
 | 
					        self.high_cut = 4000
 | 
				
			||||||
		self.bpf_transition_bw = 320 #Hz, and this is a constant
 | 
					        self.bpf_transition_bw = 320 #Hz, and this is a constant
 | 
				
			||||||
		self.ddc_transition_bw_rate = 0.15 # of the IF sample rate
 | 
					        self.ddc_transition_bw_rate = 0.15 # of the IF sample rate
 | 
				
			||||||
		self.running = False
 | 
					        self.running = False
 | 
				
			||||||
		self.audio_compression = "none"
 | 
					        self.secondary_processes_running = False
 | 
				
			||||||
		self.fft_compression = "none"
 | 
					        self.audio_compression = "none"
 | 
				
			||||||
		self.demodulator = "nfm"
 | 
					        self.fft_compression = "none"
 | 
				
			||||||
		self.name = "csdr"
 | 
					        self.demodulator = "nfm"
 | 
				
			||||||
		self.format_conversion = "csdr convert_u8_f"
 | 
					        self.name = "csdr"
 | 
				
			||||||
		self.base_bufsize = 512
 | 
					        self.format_conversion = "csdr convert_u8_f"
 | 
				
			||||||
		self.nc_port = 4951
 | 
					        self.base_bufsize = 512
 | 
				
			||||||
		self.csdr_dynamic_bufsize = False
 | 
					        self.nc_port = 4951
 | 
				
			||||||
		self.csdr_print_bufsizes = False
 | 
					        self.csdr_dynamic_bufsize = False
 | 
				
			||||||
		self.csdr_through = False
 | 
					        self.csdr_print_bufsizes = False
 | 
				
			||||||
		self.squelch_level = 0
 | 
					        self.csdr_through = False
 | 
				
			||||||
		self.fft_averages = 50
 | 
					        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):
 | 
					    def chain(self,which):
 | 
				
			||||||
		any_chain_base="nc -v 127.0.0.1 {nc_port} | "
 | 
					        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_dynamic_bufsize: any_chain_base+="csdr setbuf {start_bufsize} | "
 | 
				
			||||||
		if self.csdr_through: any_chain_base+="csdr through | "
 | 
					        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 | "
 | 
					        any_chain_base+=self.format_conversion+(" | " if  self.format_conversion!="" else "") ##"csdr flowcontrol {flowcontrol} auto 1.5 10 | "
 | 
				
			||||||
		if which == "fft":
 | 
					        if which == "fft":
 | 
				
			||||||
			fft_chain_base = any_chain_base+"csdr fft_cc {fft_size} {fft_block_size} | " + \
 | 
					            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 logpower_cf -70 | " if self.fft_averages == 0 else "csdr logaveragepower_cf -70 {fft_size} {fft_averages} | ") + \
 | 
				
			||||||
				"csdr fft_exchange_sides_ff {fft_size}"
 | 
					                "csdr fft_exchange_sides_ff {fft_size}"
 | 
				
			||||||
			if self.fft_compression=="adpcm":
 | 
					            if self.fft_compression=="adpcm":
 | 
				
			||||||
				return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}"
 | 
					                return fft_chain_base+" | csdr compress_fft_adpcm_f_u8 {fft_size}"
 | 
				
			||||||
			else:
 | 
					            else:
 | 
				
			||||||
				return fft_chain_base
 | 
					                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_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.secondary_demodulator:
 | 
				
			||||||
		if self.audio_compression=="adpcm":
 | 
					            chain_begin+="tee {iqtee_pipe} | "
 | 
				
			||||||
			chain_end = " | csdr encode_ima_adpcm_i16_u8"
 | 
					            chain_begin+="tee {iqtee_pipe2} | "
 | 
				
			||||||
		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
 | 
					        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
 | 
					        if self.audio_compression=="adpcm":
 | 
				
			||||||
		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
 | 
					            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):
 | 
					    def secondary_chain(self, which):
 | 
				
			||||||
		self.audio_compression = what
 | 
					        secondary_chain_base="cat {input_pipe} | "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_fft_compression(self,what):
 | 
					        if which == "fft":
 | 
				
			||||||
		self.fft_compression = what
 | 
					            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):
 | 
					CSDR_FIXED_BUFSIZE=1 csdr realpart_cf | \
 | 
				
			||||||
		if self.fft_compression=="none": return self.fft_size*4
 | 
					CSDR_FIXED_BUFSIZE=1 csdr binary_slicer_f_u8 | \
 | 
				
			||||||
		if self.fft_compression=="adpcm": return (self.fft_size/2)+(10/2)
 | 
					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):
 | 
					    def set_secondary_demodulator(self, what):
 | 
				
			||||||
		#to change this, restart is required
 | 
					        self.secondary_demodulator = what
 | 
				
			||||||
		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 if_samp_rate(self):
 | 
					    def secondary_fft_block_size(self):
 | 
				
			||||||
		return self.samp_rate/self.decimation
 | 
					        return (self.samp_rate/self.decimation)/self.fft_fps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_name(self):
 | 
					    def secondary_decimation(self, which):
 | 
				
			||||||
		return self.name
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_output_rate(self):
 | 
					    def secondary_bpf_cutoff(self, which):
 | 
				
			||||||
		return self.output_rate
 | 
					        if self.secondary_demodulator == "bpsk31":
 | 
				
			||||||
 | 
					             return 31.25 / self.if_samp_rate()
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_output_rate(self,output_rate):
 | 
					    def secondary_bpf_transition_bw(self, which):
 | 
				
			||||||
		self.output_rate=output_rate
 | 
					        if self.secondary_demodulator == "bpsk31":
 | 
				
			||||||
		self.set_samp_rate(self.samp_rate) #as it depends on output_rate
 | 
					            return (31.25 / 2) * self.if_samp_rate()
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_demodulator(self,demodulator):
 | 
					    def start_secondary_demodulator(self):
 | 
				
			||||||
		#to change this, restart is required
 | 
					        if(not self.secondary_demodulator): return
 | 
				
			||||||
		self.demodulator=demodulator
 | 
					        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):
 | 
					        print "[openwebrx-dsp-plugin:csdr] secondary command (fft) =", secondary_command_fft
 | 
				
			||||||
		return self.demodulator
 | 
					        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):
 | 
					        #open control pipes for csdr and send initialization data
 | 
				
			||||||
		#to change this, restart is required
 | 
					        if self.secondary_shift_pipe != None:
 | 
				
			||||||
		self.fft_size=fft_size
 | 
					            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):
 | 
					    def set_secondary_offset_freq(self, value):
 | 
				
			||||||
		#to change this, restart is required
 | 
					        self.secondary_offset_freq=value
 | 
				
			||||||
		self.fft_fps=fft_fps
 | 
					        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):
 | 
					    def stop_secondary_demodulator(self):
 | 
				
			||||||
		#to change this, restart is required
 | 
					        if self.secondary_processes_running == False: return
 | 
				
			||||||
		self.fft_averages=fft_averages
 | 
					        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):
 | 
					    def read_secondary_demod(self, size):
 | 
				
			||||||
		if self.fft_averages == 0: return self.samp_rate/self.fft_fps
 | 
					        return self.secondary_process_demod.stdout.read(size)
 | 
				
			||||||
		else: return self.samp_rate/self.fft_fps/self.fft_averages
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_format_conversion(self,format_conversion):
 | 
					    def read_secondary_fft(self, size):
 | 
				
			||||||
		self.format_conversion=format_conversion
 | 
					        return self.secondary_process_fft.stdout.read(size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_offset_freq(self,offset_freq):
 | 
					    def set_audio_compression(self,what):
 | 
				
			||||||
		self.offset_freq=offset_freq
 | 
					        self.audio_compression = what
 | 
				
			||||||
		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):
 | 
					    def set_fft_compression(self,what):
 | 
				
			||||||
		self.low_cut=low_cut
 | 
					        self.fft_compression = what
 | 
				
			||||||
		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):
 | 
					    def get_fft_bytes_to_read(self):
 | 
				
			||||||
		return [self.low_cut, self.high_cut]
 | 
					        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):
 | 
					    def set_samp_rate(self,samp_rate):
 | 
				
			||||||
		self.squelch_level=squelch_level
 | 
					        #to change this, restart is required
 | 
				
			||||||
		if self.running:
 | 
					        self.samp_rate=samp_rate
 | 
				
			||||||
			self.squelch_pipe_file.write( "%g\n"%(float(self.squelch_level)) )
 | 
					        self.decimation=1
 | 
				
			||||||
			self.squelch_pipe_file.flush()
 | 
					        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):
 | 
					    def if_samp_rate(self):
 | 
				
			||||||
		if self.running:
 | 
					        return self.samp_rate/self.decimation
 | 
				
			||||||
			line=self.smeter_pipe_file.readline()
 | 
					 | 
				
			||||||
			return float(line[:-1])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def mkfifo(self,path):
 | 
					    def get_name(self):
 | 
				
			||||||
		try:
 | 
					        return self.name
 | 
				
			||||||
			os.unlink(path)
 | 
					 | 
				
			||||||
		except:
 | 
					 | 
				
			||||||
			pass
 | 
					 | 
				
			||||||
		os.mkfifo(path)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def ddc_transition_bw(self):
 | 
					    def get_output_rate(self):
 | 
				
			||||||
		return self.ddc_transition_bw_rate*(self.if_samp_rate()/float(self.samp_rate))
 | 
					        return self.output_rate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def start(self):
 | 
					    def set_output_rate(self,output_rate):
 | 
				
			||||||
		command_base=self.chain(self.demodulator)
 | 
					        self.output_rate=output_rate
 | 
				
			||||||
 | 
					        self.set_samp_rate(self.samp_rate) #as it depends on output_rate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#create control pipes for csdr
 | 
					    def set_demodulator(self,demodulator):
 | 
				
			||||||
		pipe_base_path="/tmp/openwebrx_pipe_{myid}_".format(myid=id(self))
 | 
					        #to change this, restart is required
 | 
				
			||||||
		self.bpf_pipe = self.shift_pipe = self.squelch_pipe = self.smeter_pipe = None
 | 
					        self.demodulator=demodulator
 | 
				
			||||||
		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)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#run the command
 | 
					    def get_demodulator(self):
 | 
				
			||||||
		command=command_base.format( bpf_pipe=self.bpf_pipe, shift_pipe=self.shift_pipe, decimation=self.decimation, \
 | 
					        return self.demodulator
 | 
				
			||||||
			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
 | 
					    def set_fft_size(self,fft_size):
 | 
				
			||||||
		#code.interact(local=locals())
 | 
					        #to change this, restart is required
 | 
				
			||||||
		my_env=os.environ.copy()
 | 
					        self.fft_size=fft_size
 | 
				
			||||||
		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
 | 
					    def set_fft_fps(self,fft_fps):
 | 
				
			||||||
		if self.bpf_pipe != None:
 | 
					        #to change this, restart is required
 | 
				
			||||||
			self.bpf_pipe_file=open(self.bpf_pipe,"w")
 | 
					        self.fft_fps=fft_fps
 | 
				
			||||||
			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 read(self,size):
 | 
					    def set_fft_averages(self,fft_averages):
 | 
				
			||||||
		return self.process.stdout.read(size)
 | 
					        #to change this, restart is required
 | 
				
			||||||
 | 
					        self.fft_averages=fft_averages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def stop(self):
 | 
					    def fft_block_size(self):
 | 
				
			||||||
		os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
 | 
					        if self.fft_averages == 0: return self.samp_rate/self.fft_fps
 | 
				
			||||||
		#if(self.process.poll()!=None):return # returns None while subprocess is running
 | 
					        else: return self.samp_rate/self.fft_fps/self.fft_averages
 | 
				
			||||||
		#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 restart(self):
 | 
					    def set_format_conversion(self,format_conversion):
 | 
				
			||||||
		self.stop()
 | 
					        self.format_conversion=format_conversion
 | 
				
			||||||
		self.start()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __del__(self):
 | 
					    def set_offset_freq(self,offset_freq):
 | 
				
			||||||
		self.stop()
 | 
					        self.offset_freq=offset_freq
 | 
				
			||||||
		del(self.process)
 | 
					        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)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user