multi-sdr capabilities!
This commit is contained in:
		| @@ -71,12 +71,6 @@ fft_fps=9 | ||||
| fft_size=4096 #Should be power of 2 | ||||
| fft_voverlap_factor=0.3 #If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram. | ||||
|  | ||||
| # samp_rate = 250000 | ||||
| samp_rate = 2400000 | ||||
| center_freq = 144250000 | ||||
| rf_gain = 5 #in dB. For an RTL-SDR, rf_gain=0 will set the tuner to auto gain mode, else it will be in manual gain mode. | ||||
| ppm = 0 | ||||
|  | ||||
| audio_compression="adpcm" #valid values: "adpcm", "none" | ||||
| fft_compression="adpcm" #valid values: "adpcm", "none" | ||||
|  | ||||
| @@ -104,7 +98,30 @@ Note: if you experience audio underruns while CPU usage is 100%, you can: | ||||
| # You can use other SDR hardware as well, by giving your own command that outputs the I/Q samples... Some examples of configuration are available here (default is RTL-SDR): | ||||
|  | ||||
| # valid: "rtl_sdr", "sdrplay", "hackrf" | ||||
| rtl_type = "rtl_sdr" | ||||
| #rtl_type = "sdrplay" | ||||
|  | ||||
| sdrs = { | ||||
|     "rtlsdr": { | ||||
|         "name": "RTL-SDR USB Stick", | ||||
|         "type": "rtl_sdr", | ||||
|         "center_freq": 438800000, | ||||
|         "rf_gain": 30, | ||||
|         "samp_rate": 2400000, | ||||
|         "ppm": 0, | ||||
|         "start_freq": 439275000, | ||||
|         "start_mod": "nfm" | ||||
|     }, | ||||
|     "sdrplay": { | ||||
|         "name": "SDRPlay RSP2", | ||||
|         "type": "sdrplay", | ||||
|         "center_freq": 14150000, | ||||
|         "rf_gain": 30, | ||||
|         "samp_rate": 500000, | ||||
|         "ppm": 0, | ||||
|         "start_freq": 14070000, | ||||
|         "start_mod": "usb" | ||||
|     } | ||||
| } | ||||
|  | ||||
| # >> RTL-SDR via rtl_sdr | ||||
| #start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm) | ||||
| @@ -168,10 +185,7 @@ client_audio_buffer_size = 5 | ||||
| # - also increase the latency | ||||
| # - decrease the chance of audio underruns | ||||
|  | ||||
| start_freq = center_freq | ||||
| start_mod = "nfm" #nfm, am, lsb, usb, cw | ||||
|  | ||||
| iq_server_port = 4951 #TCP port for ncat to listen on. It will send I/Q data over its connections, for internal use in OpenWebRX. It is only accessible from the localhost by default. | ||||
| iq_port_range = [4950, 4960] #TCP port for range ncat to listen on. It will send I/Q data over its connections, for internal use in OpenWebRX. It is only accessible from the localhost by default. | ||||
|  | ||||
| #access_log = "~/openwebrx_access.log" | ||||
|  | ||||
|   | ||||
| @@ -28,7 +28,7 @@ class PropertyManager(object): | ||||
|         return PropertyManager.sharedInstance | ||||
|  | ||||
|     def collect(self, *props): | ||||
|         return PropertyManager(dict((name, self.getProperty(name)) for name in props)) | ||||
|         return PropertyManager(dict((name, self.getProperty(name) if self.hasProperty(name) else Property()) for name in props)) | ||||
|  | ||||
|     def __init__(self, properties = None): | ||||
|         self.properties = {} | ||||
| @@ -52,10 +52,15 @@ class PropertyManager(object): | ||||
|         return self.getPropertyValue(name) | ||||
|  | ||||
|     def __setitem__(self, name, value): | ||||
|         if not self.hasProperty(name): | ||||
|             self.add(name, Property()) | ||||
|         self.getProperty(name).setValue(value) | ||||
|  | ||||
|     def hasProperty(self, name): | ||||
|         return name in self.properties | ||||
|  | ||||
|     def getProperty(self, name): | ||||
|         if not name in self.properties: | ||||
|         if not self.hasProperty(name): | ||||
|             self.add(name, Property()) | ||||
|         return self.properties[name] | ||||
|  | ||||
| @@ -66,6 +71,16 @@ class PropertyManager(object): | ||||
|         self.callbacks.append(callback) | ||||
|         return self | ||||
|  | ||||
|     def unwire(self, callback): | ||||
|         self.callbacks.remove(callback) | ||||
|         return self | ||||
|  | ||||
|     def defaults(self, other_pm): | ||||
|         for (key, p) in self.properties.items(): | ||||
|             if p.getValue() is None: | ||||
|                 p.setValue(other_pm[key]) | ||||
|         return self | ||||
|  | ||||
| class RequirementMissingException(Exception): | ||||
|     pass | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import mimetypes | ||||
| from owrx.websocket import WebSocketConnection | ||||
| from owrx.config import PropertyManager | ||||
| from owrx.source import SpectrumThread, DspManager, CpuUsageThread | ||||
| from owrx.source import SpectrumThread, DspManager, CpuUsageThread, SdrService | ||||
| import json | ||||
| import os | ||||
| from datetime import datetime | ||||
| @@ -62,8 +62,76 @@ class IndexController(AssetsController): | ||||
|         self.serve_file("index.wrx", "text/html") | ||||
|  | ||||
| class OpenWebRxClient(object): | ||||
|     config_keys = ["waterfall_colors", "waterfall_min_level", "waterfall_max_level", | ||||
|                    "waterfall_auto_level_margin", "lfo_offset", "samp_rate", "fft_size", "fft_fps", | ||||
|                    "audio_compression", "fft_compression", "max_clients", "start_mod", | ||||
|                    "client_audio_buffer_size", "start_freq", "center_freq"] | ||||
|     def __init__(self, conn): | ||||
|         self.conn = conn | ||||
|  | ||||
|         self.dsp = None | ||||
|         self.sdr = None | ||||
|         self.configProps = None | ||||
|  | ||||
|         pm = PropertyManager.getSharedInstance() | ||||
|  | ||||
|         self.setSdr() | ||||
|  | ||||
|         # send receiver info | ||||
|         receiver_keys = ["receiver_name", "receiver_location", "receiver_qra", "receiver_asl",  "receiver_gps", | ||||
|                          "photo_title", "photo_desc"] | ||||
|         receiver_details = dict((key, pm.getPropertyValue(key)) for key in receiver_keys) | ||||
|         self.write_receiver_details(receiver_details) | ||||
|  | ||||
|         CpuUsageThread.getSharedInstance().add_client(self) | ||||
|  | ||||
|     def sendConfig(self, key, value): | ||||
|         config = dict((key, self.configProps[key]) for key in OpenWebRxClient.config_keys) | ||||
|         # TODO mathematical properties? hmmmm | ||||
|         config["start_offset_freq"] = self.configProps["start_freq"] - self.configProps["center_freq"] | ||||
|         self.write_config(config) | ||||
|     def setSdr(self, id = None): | ||||
|         self.stopDsp() | ||||
|  | ||||
|         if self.configProps is not None: | ||||
|             self.configProps.unwire(self.sendConfig) | ||||
|  | ||||
|         self.sdr = SdrService.getSource(id) | ||||
|         self.sdr.start() | ||||
|  | ||||
|         # send initial config | ||||
|         self.configProps = self.sdr.getProps().collect(*OpenWebRxClient.config_keys).defaults(PropertyManager.getSharedInstance()) | ||||
|  | ||||
|         self.configProps.wire(self.sendConfig) | ||||
|         self.sendConfig(None, None) | ||||
|  | ||||
|         self.sdr.spectrumThread.add_client(self) | ||||
|  | ||||
|     def startDsp(self): | ||||
|         if self.dsp is None: | ||||
|             self.dsp = DspManager(self, self.sdr) | ||||
|             self.dsp.start() | ||||
|  | ||||
|     def stopDsp(self): | ||||
|         if self.dsp is not None: | ||||
|             self.dsp.stop() | ||||
|             self.dsp = None | ||||
|         if self.sdr is not None: | ||||
|             self.sdr.spectrumThread.remove_client(self) | ||||
|         # TODO: this should be disabled somehow, just not with the dsp | ||||
|         #CpuUsageThread.getSharedInstance().remove_client(self) | ||||
|  | ||||
|     def setParams(self, params): | ||||
|         # only the keys in the protected property manager can be overridden from the web | ||||
|         protected = self.sdr.getProps().collect("samp_rate", "center_freq", "rf_gain", "type") \ | ||||
|             .defaults(PropertyManager.getSharedInstance()) | ||||
|         for key, value in params.items(): | ||||
|             protected[key] = value | ||||
|  | ||||
|     def setDspProperties(self, params): | ||||
|         for key, value in params.items(): | ||||
|             self.dsp.setProperty(key, value) | ||||
|  | ||||
|     def write_spectrum_data(self, data): | ||||
|         self.conn.send(bytes([0x01]) + data) | ||||
|     def write_dsp_data(self, data): | ||||
| @@ -90,8 +158,6 @@ class WebSocketMessageHandler(object): | ||||
|         self.dsp = None | ||||
|  | ||||
|     def handleTextMessage(self, conn, message): | ||||
|         pm = PropertyManager.getSharedInstance() | ||||
|  | ||||
|         if (message[:16] == "SERVER DE CLIENT"): | ||||
|             # maybe put some more info in there? nothing to store yet. | ||||
|             self.handshake = "completed" | ||||
| @@ -99,31 +165,6 @@ class WebSocketMessageHandler(object): | ||||
|  | ||||
|             self.client = OpenWebRxClient(conn) | ||||
|  | ||||
|             config_keys = ["waterfall_colors", "waterfall_min_level", "waterfall_max_level", | ||||
|                            "waterfall_auto_level_margin", "lfo_offset", "samp_rate", "fft_size", "fft_fps", | ||||
|                            "audio_compression", "fft_compression", "max_clients", "start_mod", | ||||
|                            "client_audio_buffer_size", "start_freq", "center_freq"] | ||||
|  | ||||
|             configProps = pm.collect(*config_keys) | ||||
|  | ||||
|             def sendConfig(key, value): | ||||
|                 config = dict((key, configProps[key]) for key in config_keys) | ||||
|                 config["start_offset_freq"] = configProps["start_freq"] - configProps["center_freq"] | ||||
|                 self.client.write_config(config) | ||||
|  | ||||
|             configProps.wire(sendConfig) | ||||
|             sendConfig(None, None) | ||||
|  | ||||
|             receiver_keys = ["receiver_name", "receiver_location", "receiver_qra", "receiver_asl",  "receiver_gps", | ||||
|                              "photo_title", "photo_desc"] | ||||
|             receiver_details = dict((key, pm.getPropertyValue(key)) for key in receiver_keys) | ||||
|             self.client.write_receiver_details(receiver_details) | ||||
|  | ||||
|             SpectrumThread.getSharedInstance().add_client(self.client) | ||||
|             CpuUsageThread.getSharedInstance().add_client(self.client) | ||||
|  | ||||
|             self.dsp = DspManager(self.client) | ||||
|  | ||||
|             return | ||||
|  | ||||
|         if not self.handshake: | ||||
| @@ -132,20 +173,23 @@ class WebSocketMessageHandler(object): | ||||
|  | ||||
|         try: | ||||
|             message = json.loads(message) | ||||
|             if message["type"] == "dspcontrol": | ||||
|                 if "params" in message: | ||||
|                     params = message["params"] | ||||
|                     for key, value in params.items(): | ||||
|                         self.dsp.setProperty(key, value) | ||||
|             if "type" in message: | ||||
|                 if message["type"] == "dspcontrol": | ||||
|                     if "action" in message and message["action"] == "start": | ||||
|                         self.client.startDsp() | ||||
|  | ||||
|                 if "action" in message and message["action"] == "start": | ||||
|                     self.dsp.start() | ||||
|                     if "params" in message: | ||||
|                         params = message["params"] | ||||
|                         self.client.setDspProperties(params) | ||||
|  | ||||
|             if message["type"] == "config": | ||||
|                 for key, value in message["params"].items(): | ||||
|                     # only the keys in the protected property manager can be overridden from the web | ||||
|                     protected = pm.collect("samp_rate", "center_freq", "rf_gain", "rtl_type") | ||||
|                     protected[key] = value | ||||
|                 if message["type"] == "config": | ||||
|                     if "params" in message: | ||||
|                         self.client.setParams(message["params"]) | ||||
|                 if message["type"] == "setsdr": | ||||
|                     if "params" in message: | ||||
|                         self.client.setSdr(message["params"]["sdr"]) | ||||
|             else: | ||||
|                 print("received message without type: {0}".format(message)) | ||||
|  | ||||
|         except json.JSONDecodeError: | ||||
|             print("message is not json: {0}".format(message)) | ||||
| @@ -155,10 +199,7 @@ class WebSocketMessageHandler(object): | ||||
|  | ||||
|     def handleClose(self, conn): | ||||
|         if self.client: | ||||
|             SpectrumThread.getSharedInstance().remove_client(self.client) | ||||
|             CpuUsageThread.getSharedInstance().remove_client(self.client) | ||||
|         if self.dsp: | ||||
|             self.dsp.stop() | ||||
|             self.client.stopDsp() | ||||
|  | ||||
| class WebSocketController(Controller): | ||||
|     def handle_request(self): | ||||
|   | ||||
							
								
								
									
										151
									
								
								owrx/source.py
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								owrx/source.py
									
									
									
									
									
								
							| @@ -6,47 +6,87 @@ import time | ||||
| import os | ||||
| import signal | ||||
|  | ||||
| class RtlNmuxSource(object): | ||||
|     types = { | ||||
|         "rtl_sdr": { | ||||
|             "command": "rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -", | ||||
|             "format_conversion": "csdr convert_u8_f" | ||||
|         }, | ||||
|         "hackrf": { | ||||
|             "command": "hackrf_transfer -s {samp_rate} -f {center_freq} -g {rf_gain} -l{lna_gain} -a{rf_amp} -r-", | ||||
|             "format_conversion": "csdr convert_s8_f" | ||||
|         }, | ||||
|         "sdrplay": { | ||||
|             "command": "rx_sdr -F CF32 -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -", | ||||
|             "format_conversion": None, | ||||
|             "sleep": 1 | ||||
|         } | ||||
|     } | ||||
| class SdrService(object): | ||||
|     sdrProps = None | ||||
|     sources = {} | ||||
|     lastPort = None | ||||
|     @staticmethod | ||||
|     def getNextPort(): | ||||
|         pm = PropertyManager.getSharedInstance() | ||||
|         (start, end) = pm["iq_port_range"] | ||||
|         if SdrService.lastPort is None: | ||||
|             SdrService.lastPort = start | ||||
|         else: | ||||
|             SdrService.lastPort += 1 | ||||
|             if SdrService.lastPort > end: | ||||
|                 raise IndexError("no more available ports to start more sdrs") | ||||
|         return SdrService.lastPort | ||||
|     @staticmethod | ||||
|     def getSource(id = None): | ||||
|         if SdrService.sdrProps is None: | ||||
|             pm = PropertyManager.getSharedInstance() | ||||
|             def loadIntoPropertyManager(dict: dict): | ||||
|                 propertyManager = PropertyManager() | ||||
|                 for (name, value) in dict.items(): | ||||
|                     propertyManager[name] = value | ||||
|                 return propertyManager | ||||
|             SdrService.sdrProps = dict((name, loadIntoPropertyManager(value)) for (name, value) in pm["sdrs"].items()) | ||||
|             print(SdrService.sdrProps) | ||||
|         if id is None: | ||||
|             # TODO: configure default sdr in config? right now it will pick the first one off the list. | ||||
|             id = list(SdrService.sdrProps.keys())[0] | ||||
|         if not id in SdrService.sources: | ||||
|             SdrService.sources[id] = SdrSource(SdrService.sdrProps[id], SdrService.getNextPort()) | ||||
|         return SdrService.sources[id] | ||||
|  | ||||
|     def setup(self): | ||||
|         self.props = props = PropertyManager.getSharedInstance().collect( | ||||
|             "rtl_type", "samp_rate", "nmux_memory", "iq_server_port", "center_freq", "ppm", | ||||
|             "rf_gain", "lna_gain", "rf_amp" | ||||
|         ) | ||||
| sdr_types = { | ||||
|     "rtl_sdr": { | ||||
|         "command": "rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -", | ||||
|         "format_conversion": "csdr convert_u8_f" | ||||
|     }, | ||||
|     "hackrf": { | ||||
|         "command": "hackrf_transfer -s {samp_rate} -f {center_freq} -g {rf_gain} -l{lna_gain} -a{rf_amp} -r-", | ||||
|         "format_conversion": "csdr convert_s8_f" | ||||
|     }, | ||||
|     "sdrplay": { | ||||
|         "command": "rx_sdr -F CF32 -s {samp_rate} -f {center_freq} -p {ppm} -g {rf_gain} -", | ||||
|         "format_conversion": None, | ||||
|         "sleep": 1 | ||||
|     } | ||||
| } | ||||
|  | ||||
| class SdrSource(object): | ||||
|     def __init__(self, props, port): | ||||
|         self.props = props | ||||
|         self.rtlProps = self.props.collect( | ||||
|             "type", "samp_rate", "nmux_memory", "center_freq", "ppm", "rf_gain", "lna_gain", "rf_amp" | ||||
|         ).defaults(PropertyManager.getSharedInstance()) | ||||
|  | ||||
|         def restart(name, value): | ||||
|             print("restarting rtl source due to property change: {0} changed to {1}".format(name, value)) | ||||
|             print("restarting sdr source due to property change: {0} changed to {1}".format(name, value)) | ||||
|             self.stop() | ||||
|             self.start() | ||||
|         props.wire(restart) | ||||
|         self.rtlProps.wire(restart) | ||||
|         self.port = port | ||||
|         self.monitor = None | ||||
|  | ||||
|         self.start() | ||||
|     def getProps(self): | ||||
|         return self.props | ||||
|  | ||||
|     def getPort(self): | ||||
|         return self.port | ||||
|  | ||||
|     def start(self): | ||||
|         if self.monitor: return | ||||
|  | ||||
|         props = self.props | ||||
|         props = self.rtlProps | ||||
|  | ||||
|         featureDetector = FeatureDetector() | ||||
|         if not featureDetector.is_available(props["rtl_type"]): | ||||
|         if not featureDetector.is_available(props["type"]): | ||||
|             print("The RTL source type {0} is not available. please check requirements.".format(props["rtl_type"])) | ||||
|             return | ||||
|  | ||||
|         self.params = RtlNmuxSource.types[props["rtl_type"]] | ||||
|         self.params = sdr_types[props["type"]] | ||||
|  | ||||
|         start_sdr_command = self.params["command"].format( | ||||
|             samp_rate = props["samp_rate"], | ||||
| @@ -67,7 +107,7 @@ class RtlNmuxSource(object): | ||||
|             print("[RtlNmuxSource] Error: nmux_bufsize or nmux_bufcnt is zero. These depend on nmux_memory and samp_rate options in config_webrx.py") | ||||
|             return | ||||
|         print("[RtlNmuxSource] nmux_bufsize = %d, nmux_bufcnt = %d" % (nmux_bufsize, nmux_bufcnt)) | ||||
|         cmd = start_sdr_command + " | nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1" % (nmux_bufsize, nmux_bufcnt, props["iq_server_port"]) | ||||
|         cmd = start_sdr_command + " | nmux --bufsize %d --bufcnt %d --port %d --address 127.0.0.1" % (nmux_bufsize, nmux_bufcnt, self.port) | ||||
|         self.process = subprocess.Popen(cmd, shell=True, preexec_fn=os.setpgrp) | ||||
|         print("[RtlNmuxSource] Started rtl source: " + cmd) | ||||
|  | ||||
| @@ -75,38 +115,36 @@ class RtlNmuxSource(object): | ||||
|         def wait_for_process_to_end(): | ||||
|             rc = self.process.wait() | ||||
|             print("[RtlNmuxSource] shut down with RC={0}".format(rc)) | ||||
|             self.monitor = None | ||||
|  | ||||
|         self.monitor = threading.Thread(target = wait_for_process_to_end) | ||||
|         self.monitor.start() | ||||
|  | ||||
|         self.spectrumThread = SpectrumThread(self) | ||||
|  | ||||
|     def stop(self): | ||||
|         os.killpg(os.getpgid(self.process.pid), signal.SIGTERM) | ||||
|         self.monitor.join() | ||||
|         if "sleep" in self.params: | ||||
|             time.sleep(self.params["sleep"]) | ||||
|  | ||||
| class SpectrumThread(threading.Thread): | ||||
|     sharedInstance = None | ||||
|     @staticmethod | ||||
|     def getSharedInstance(): | ||||
|         if SpectrumThread.sharedInstance is None: | ||||
|             SpectrumThread.sharedInstance = SpectrumThread() | ||||
|             SpectrumThread.sharedInstance.start() | ||||
|         return SpectrumThread.sharedInstance | ||||
|  | ||||
|     def __init__(self): | ||||
| class SpectrumThread(object): | ||||
|     def __init__(self, sdrSource): | ||||
|         self.clients = [] | ||||
|         self.doRun = True | ||||
|         super().__init__() | ||||
|         self.doRun = False | ||||
|         self.sdrSource = sdrSource | ||||
|  | ||||
|     def start(self): | ||||
|         threading.Thread(target = self.run).start() | ||||
|  | ||||
|     def run(self): | ||||
|         props = PropertyManager.getSharedInstance().collect( | ||||
|         props = self.sdrSource.props.collect( | ||||
|             "samp_rate", "fft_size", "fft_fps", "fft_voverlap_factor", "fft_compression", | ||||
|             "csdr_dynamic_bufsize", "csdr_print_bufsizes", "csdr_through", "iq_server_port" | ||||
|         ) | ||||
|             "csdr_dynamic_bufsize", "csdr_print_bufsizes", "csdr_through" | ||||
|         ).defaults(PropertyManager.getSharedInstance()) | ||||
|  | ||||
|         dsp = csdr.dsp() | ||||
|         dsp.nc_port = props["iq_server_port"] | ||||
|         dsp.nc_port = self.sdrSource.getPort() | ||||
|         dsp.set_demodulator("fft") | ||||
|         props.getProperty("samp_rate").wire(dsp.set_samp_rate) | ||||
|         props.getProperty("fft_size").wire(dsp.set_fft_size) | ||||
| @@ -146,26 +184,32 @@ class SpectrumThread(threading.Thread): | ||||
|  | ||||
|     def add_client(self, c): | ||||
|         self.clients.append(c) | ||||
|         if not self.doRun: | ||||
|             self.doRun = True | ||||
|             self.start() | ||||
|  | ||||
|     def remove_client(self, c): | ||||
|         self.clients.remove(c) | ||||
|         try: | ||||
|             self.clients.remove(c) | ||||
|         except ValueError: | ||||
|             pass | ||||
|         if not self.clients: | ||||
|             self.shutdown() | ||||
|  | ||||
|     def shutdown(self): | ||||
|         print("shutting down spectrum thread") | ||||
|         SpectrumThread.sharedInstance = None | ||||
|         self.doRun = False | ||||
|  | ||||
| class DspManager(object): | ||||
|     def __init__(self, handler): | ||||
|     def __init__(self, handler, sdrSource): | ||||
|         self.doRun = True | ||||
|         self.handler = handler | ||||
|         self.sdrSource = sdrSource | ||||
|  | ||||
|         self.localProps = PropertyManager.getSharedInstance().collect( | ||||
|         self.localProps = self.sdrSource.getProps().collect( | ||||
|             "audio_compression", "fft_compression", "digimodes_fft_size", "csdr_dynamic_bufsize", | ||||
|             "csdr_print_bufsizes", "csdr_through", "iq_server_port", "digimodes_enable", "samp_rate" | ||||
|         ) | ||||
|             "csdr_print_bufsizes", "csdr_through", "digimodes_enable", "samp_rate" | ||||
|         ).defaults(PropertyManager.getSharedInstance()) | ||||
|  | ||||
|         self.dsp = csdr.dsp() | ||||
|         #dsp_initialized=False | ||||
| @@ -175,7 +219,7 @@ class DspManager(object): | ||||
|         self.dsp.set_bpf(-4000,4000) | ||||
|         self.localProps.getProperty("digimodes_fft_size").wire(self.dsp.set_secondary_fft_size) | ||||
|  | ||||
|         self.dsp.nc_port = self.localProps["iq_server_port"] | ||||
|         self.dsp.nc_port = self.sdrSource.getPort() | ||||
|         self.dsp.csdr_dynamic_bufsize = self.localProps["csdr_dynamic_bufsize"] | ||||
|         self.dsp.csdr_print_bufsizes = self.localProps["csdr_print_bufsizes"] | ||||
|         self.dsp.csdr_through = self.localProps["csdr_through"] | ||||
| @@ -322,7 +366,10 @@ class CpuUsageThread(threading.Thread): | ||||
|         self.clients.append(c) | ||||
|  | ||||
|     def remove_client(self, c): | ||||
|         self.clients.remove(c) | ||||
|         try: | ||||
|             self.clients.remove(c) | ||||
|         except ValueError: | ||||
|             pass | ||||
|         if not self.clients: | ||||
|             self.shutdown() | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| from http.server import HTTPServer | ||||
| from owrx.http import RequestHandler | ||||
| from owrx.config import PropertyManager, FeatureDetector, RequirementMissingException | ||||
| from owrx.source import RtlNmuxSource | ||||
| from owrx.source import SdrService | ||||
| from socketserver import ThreadingMixIn | ||||
|  | ||||
| class ThreadedHttpServer(ThreadingMixIn, HTTPServer): | ||||
| @@ -19,7 +19,7 @@ def main(): | ||||
|     pm = PropertyManager.getSharedInstance() | ||||
|     for name, value in cfg.__dict__.items(): | ||||
|         if (name.startswith("__")): continue | ||||
|         pm.getProperty(name).setValue(value) | ||||
|         pm[name] = value | ||||
|  | ||||
|     featureDetector = FeatureDetector() | ||||
|     if not featureDetector.is_available("core"): | ||||
| @@ -28,9 +28,6 @@ def main(): | ||||
|         print(", ".join(featureDetector.get_requirements("core"))) | ||||
|         return | ||||
|  | ||||
|     if (pm.getPropertyValue("start_rtl_thread")): | ||||
|         RtlNmuxSource().setup() | ||||
|  | ||||
|     server = ThreadedHttpServer(('0.0.0.0', pm.getPropertyValue("web_port")), RequestHandler) | ||||
|     server.serve_forever() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl