Пример #1
0
class OpenWebRxReceiverClient(Client):
    config_keys = [
        "waterfall_colors",
        "waterfall_min_level",
        "waterfall_max_level",
        "waterfall_auto_level_margin",
        "samp_rate",
        "fft_size",
        "fft_fps",
        "audio_compression",
        "fft_compression",
        "max_clients",
        "start_mod",
        "start_freq",
        "center_freq",
        "initial_squelch_level",
        "profile_id",
    ]

    def __init__(self, conn):
        super().__init__(conn)

        self.dsp = None
        self.sdr = None
        self.configSub = None
        self.connectionProperties = {}

        try:
            ClientRegistry.getSharedInstance().addClient(self)
        except TooManyClientsException:
            self.write_backoff_message("Too many clients")
            self.close()
            raise

        pm = PropertyManager.getSharedInstance()

        self.setSdr()

        # send receiver info
        receiver_keys = [
            "receiver_name",
            "receiver_location",
            "receiver_asl",
            "receiver_gps",
            "photo_title",
            "photo_desc",
        ]
        receiver_details = dict((key, pm.getPropertyValue(key)) for key in receiver_keys)
        receiver_details["locator"] = Locator.fromCoordinates(receiver_details["receiver_gps"])
        self.write_receiver_details(receiver_details)

        self.__sendProfiles()

        features = FeatureDetector().feature_availability()
        self.write_features(features)

        CpuUsageThread.getSharedInstance().add_client(self)

    def __sendProfiles(self):
        profiles = [
            {"name": s.getName() + " " + p["name"], "id": sid + "|" + pid}
            for (sid, s) in SdrService.getSources().items()
            for (pid, p) in s.getProfiles().items()
        ]
        self.write_profiles(profiles)

    def handleTextMessage(self, conn, message):
        try:
            message = json.loads(message)
            if "type" in message:
                if message["type"] == "dspcontrol":
                    if "action" in message and message["action"] == "start":
                        self.startDsp()

                    if "params" in message:
                        params = message["params"]
                        self.setDspProperties(params)

                elif message["type"] == "config":
                    if "params" in message:
                        self.setParams(message["params"])
                elif message["type"] == "setsdr":
                    if "params" in message:
                        self.setSdr(message["params"]["sdr"])
                elif message["type"] == "selectprofile":
                    if "params" in message and "profile" in message["params"]:
                        profile = message["params"]["profile"].split("|")
                        self.setSdr(profile[0])
                        self.sdr.activateProfile(profile[1])
                elif message["type"] == "connectionproperties":
                    if "params" in message:
                        self.connectionProperties = message["params"]
                        if self.dsp:
                            self.setDspProperties(self.connectionProperties)

            else:
                logger.warning("received message without type: {0}".format(message))

        except json.JSONDecodeError:
            logger.warning("message is not json: {0}".format(message))

    def setSdr(self, id=None):
        while True:
            next = None
            if id is not None:
                next = SdrService.getSource(id)
            if next is None:
                next = SdrService.getFirstSource()
            if next is None:
                # exit condition: no sdrs available
                self.handleNoSdrsAvailable()
                return

            # exit condition: no change
            if next == self.sdr:
                return

            self.stopDsp()

            if self.configSub is not None:
                self.configSub.cancel()
                self.configSub = None

            self.sdr = next

            self.startDsp()

            # keep trying until we find a suitable SDR
            if self.sdr.getState() == SdrSource.STATE_FAILED:
                self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName()))
            else:
                break

        # send initial config
        self.setDspProperties(self.connectionProperties)

        configProps = (
            self.sdr.getProps()
            .collect(*OpenWebRxReceiverClient.config_keys)
            .defaults(PropertyManager.getSharedInstance())
        )

        def sendConfig(key, value):
            config = dict((key, configProps[key]) for key in OpenWebRxReceiverClient.config_keys)
            # TODO mathematical properties? hmmmm
            config["start_offset_freq"] = configProps["start_freq"] - configProps["center_freq"]
            # TODO this is a hack to support multiple sdrs
            config["sdr_id"] = self.sdr.getId()
            self.write_config(config)

            cf = configProps["center_freq"]
            srh = configProps["samp_rate"] / 2
            frequencyRange = (cf - srh, cf + srh)
            self.write_dial_frequendies(Bandplan.getSharedInstance().collectDialFrequencies(frequencyRange))
            bookmarks = [b.__dict__() for b in Bookmarks.getSharedInstance().getBookmarks(frequencyRange)]
            self.write_bookmarks(bookmarks)

        self.configSub = configProps.wire(sendConfig)
        sendConfig(None, None)
        self.__sendProfiles()

        self.sdr.addSpectrumClient(self)

    def handleNoSdrsAvailable(self):
        self.write_sdr_error("No SDR Devices available")

    def startDsp(self):
        if self.dsp is None and self.sdr is not None:
            self.dsp = DspManager(self, self.sdr)
            self.dsp.start()

    def close(self):
        self.stopDsp()
        CpuUsageThread.getSharedInstance().remove_client(self)
        ClientRegistry.getSharedInstance().removeClient(self)
        if self.configSub is not None:
            self.configSub.cancel()
            self.configSub = None
        super().close()

    def stopDsp(self):
        if self.dsp is not None:
            self.dsp.stop()
            self.dsp = None
        if self.sdr is not None:
            self.sdr.removeSpectrumClient(self)

    def setParams(self, params):
        # allow direct configuration only if enabled in the config
        keys = PropertyManager.getSharedInstance()["configurable_keys"]
        if not keys:
            return
        # only the keys in the protected property manager can be overridden from the web
        protected = (
            self.sdr.getProps()
            .collect(*keys)
            .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.mp_send(bytes([0x01]) + data)

    def write_dsp_data(self, data):
        self.send(bytes([0x02]) + data)

    def write_s_meter_level(self, level):
        self.send({"type": "smeter", "value": level})

    def write_cpu_usage(self, usage):
        self.mp_send({"type": "cpuusage", "value": usage})

    def write_clients(self, clients):
        self.mp_send({"type": "clients", "value": clients})

    def write_secondary_fft(self, data):
        self.send(bytes([0x03]) + data)

    def write_secondary_demod(self, data):
        message = data.decode("ascii", "replace")
        self.send({"type": "secondary_demod", "value": message})

    def write_secondary_dsp_config(self, cfg):
        self.send({"type": "secondary_config", "value": cfg})

    def write_config(self, cfg):
        self.send({"type": "config", "value": cfg})

    def write_receiver_details(self, details):
        self.send({"type": "receiver_details", "value": details})

    def write_profiles(self, profiles):
        self.send({"type": "profiles", "value": profiles})

    def write_features(self, features):
        self.send({"type": "features", "value": features})

    def write_metadata(self, metadata):
        self.send({"type": "metadata", "value": metadata})

    def write_wsjt_message(self, message):
        self.send({"type": "wsjt_message", "value": message})

    def write_dial_frequendies(self, frequencies):
        self.send({"type": "dial_frequencies", "value": frequencies})

    def write_bookmarks(self, bookmarks):
        self.send({"type": "bookmarks", "value": bookmarks})

    def write_aprs_data(self, data):
        self.send({"type": "aprs_data", "value": data})

    def write_log_message(self, message):
        self.send({"type": "log_message", "value": message})

    def write_sdr_error(self, message):
        self.send({"type": "sdr_error", "value": message})

    def write_pocsag_data(self, data):
        self.send({"type": "pocsag_data", "value": data})

    def write_backoff_message(self, reason):
        self.send({"type": "backoff", "reason": reason})
Пример #2
0
 def getDsp(self):
     with self.dspLock:
         if self.dsp is None and self.sdr is not None:
             self.dsp = DspManager(self, self.sdr)
     return self.dsp
Пример #3
0
 def startDsp(self):
     if self.dsp is None and self.sdr is not None:
         self.dsp = DspManager(self, self.sdr)
         self.dsp.start()