Ejemplo n.º 1
0
    def _recv_iq_thread(self):

        poller = zmq.Poller()
        poller.register(self._sock_iq, zmq.POLLIN)

        self._iqrxcnt = 0

        while True:
            sock = poller.poll(1.0)
            
            for s, event in sock:
                data = s.recv()
                data_vals = list(np.frombuffer(data, dtype=np.complex64))
                self._iqbuff += data_vals
                self._iqrxcnt += len(data_vals)                    
                    

            # Dont like this but it is one way to check the abort flag and at the same time
            # trigger on the global abort event.
            try:
                if wait_loop(lambda: self._stop, timeout = 0.0001) is not None:
                    log.debug("recv_iq_thread aborted")
                    break
            except AbortAllException:
                log.debug("abort all exception caught, cancelling _recv_iq_thread")
                break
Ejemplo n.º 2
0
    def _set_azel(self, az, el, timeout=.5):
        """
        This method sends the command to set the position to the rotator.
        If anything goes wrong it raises an exception
        """

        try:
            ret = self._send_ser_cmd('W{:03.0f} {:03.0f}'.format(az, el), timeout=timeout)
        except:
            raise #<--- timeout

        if not self._parse_set_reply(ret):
            estr = "Unexpected response when setting azel: '{}'".format(ret.encode('string_escape'))
            raise Error(estr)

        #Allow the controller time to settle
        wait_loop(timeout=self.ROT_SETTLETIME_SET)
Ejemplo n.º 3
0
    def _send_ser_cmd(self, cmd, timeout=.5):
        ret = None
        exc = None
        t0 = time.time()
        while ret is None and exc is None:
            try:
                ret, exc = self._ser.send(cmd)
            except ValueError:
                if time.time() - t0 > timeout:
                    raise Error("Timeout waiting for serial port to be free")
                else:
                    wait_loop(timeout=.01)

        if exc is not None:
            raise exc

        return ret
Ejemplo n.º 4
0
    def _pthr_update(self):
        while True:
            self._update_rotator()

            try:
                if not wait_loop(self._stopped, timeout = self._POLL_DT) is None:
                    log.debug("Exiting GS232B polling loop due to stop() being called")
                    break
            except:
                log.debug("Exiting GS232B polling loop due to global abort")
                break
Ejemplo n.º 5
0
    def _poll_for_rpcconnection(self):

        # try to connect to api every minute
        while len(self._rpc_unavailable) > 0:
            _unavailable = {}
            sys.stdout.flush()
            for uri, rpcaddr in self._rpc_unavailable.items():
                try:
                    self._try_rpc_connection(uri, rpcaddr)
                except Exception as e:
                    _unavailable[uri] = rpcaddr

            self._rpc_unavailable= _unavailable
            if wait_loop(self._abort_event, timeout=60) is not None:
                break
Ejemplo n.º 6
0
            def _pthr_record():
                spec = [None]*N
                ok_idx = [False] * N
                tvec   = [0.0] * N
                fvec = []
                abort.clear()
                
                t0 = time.time()
                
                last_spec = None
                for n in range(N):
                    try:

                        t0 = time.time()                            
                        tvec[n] = t0


                        dt1 = (dt - (time.time() - t0))
                        if dt1 > 2.0:
                            if abort in wait_loop([abort], timeout=dt1):
                                break
                        else:
                            time.sleep(dt1)
                            if abort.is_set():
                                break
                        
                        
                        try:
                            ret = self.get_spectrum()
                        except:
                            continue
                        

                        if len(ret) != 2:
                            raise Error("get_spectrum did not return valid freq, spec")

                        fv, sp = ret[0][::fdec], ret[1][::fdec]
                        
                        # Check if there is something new, if not skip
                        if last_spec is not None and all(sp[i] == last_spec[i] for i in range(len(sp))):
                            continue

                        last_spec = sp[:]

                        fvec, spec[n] = fv, sp 
                        ok_idx[n] = True

                        

                    except Exception as e:
                        log.error("Error {} while recording spectrum. Ignoring and continuing: {}".format(e.__class__.__name__, e))
               
                spec = [[0.0]*len(fvec) if x is None else list(x) for x in spec]

                lens = [len(s) for s in spec]
                if not all([l == lens[0] for l in lens]):
                    raise Error("Unexpected error recording spectra. Not all spectra are same length")
                    

                if len(fvec) == 0:
                    raise Error("No data recorded")

                # Trim data that wasnt filled (in case abort wwas called)
                spec = spec[:(n+1)]
                tvec = tvec[:(n+1)]
                ok_idx = ok_idx[:(n+1)]

                spec = np.array(spec)
                # Get rid of bad data unless zeroes are requested
                if not add_zeroes:                    
                    spec = spec[ok_idx, :]
                    tvec = [tvec[k] for k,ok in enumerate(ok_idx) if ok]
                    
                dvec = [conv_time(t, to="datetime", float_t="unix") for t in tvec]
                return fvec, dvec, spec
Ejemplo n.º 7
0
    def execute_pass(self, i):
        """
        Method to execute a pass on the ground station.

        Will initiate tracking of the satellite and perform all the communications
        that have been defined.

        For each communication, it will wait for a reply before continuing. If
        no reply is received it will retry as many times as specified in the schedule.

        If no reply is expected, the schedule should specify retries=0

        Args:
            i (int): Pass number from the schedule
        """

        # Wrap everything in try/except/finally to make sure that
        # if anything bad happens during a pass
        # it does not make everything fall over.
        try:
            stop = lambda: self._stop
            not_tracking = lambda: self.gs.state.state != self.gs.state.TRACKING

            metadata = self.schedule.passes[i].metadata
            p = self.schedule.passes[i].pass_data
            p.nid = self.schedule.passes[i].nid

            if self.enforce_signoffs and p.nid <= 0:
                log.warning(
                    "The schedule does not have enough signoffs, but NID = {} is not a real satellite so allowing scheduler to continue anyway"
                    .format(p.nid))
            elif self.enforce_signoffs:
                if not 'signoffs' in metadata.keys() or len(
                        metadata['signoffs']) < self.enforce_signoffs:
                    log.error(
                        "The schedule does not have enough signoffs. At least {} are required."
                        .format(self.enforce_signoffs))
                    return

            #
            # 2) Slew to start and wait for satellite to come into view
            #
            self.gs.start_track(p, compute_ant_points=self.compute_ant_points)

            #
            # Give the GS a second to initiate the pass_id variable, then save schedule
            # to log.
            #
            time.sleep(1.0)
            log.debug("Storing schedule in database. pass_id = {}".format(
                self.gs.state.pass_id[1]))

            try:
                self.gs._passlog.put(module=__name__,
                                     pass_id=self.gs.state.pass_id[1],
                                     key="schedule",
                                     value=self.schedule.passes[i].to_json())
            except Exception as e:
                log.exception(
                    "Exception trying to insert schedule in database: {}: {}")

            if 'signoffs' in metadata.keys():
                log.info("The pass has been signed by {}".format(
                    metadata['signoffs']))

                try:
                    self.gs._passlog.put(module=__name__,
                                         pass_id=self.gs.state.pass_id[1],
                                         key="signoffs",
                                         value=metadata['signoffs'])
                except Exception as e:
                    log.exception(
                        "Exception trying to insert signoffs in database: {}: {}"
                    )

            log.info("Waiting for pass")
            if stop in wait_loop(
                [stop, lambda: self.gs.state.state == self.gs.state.TRACKING],
                    timeout=None,
                    dt=.5):
                log.debug("execute_pass aborted with stop event")
                return

            #
            # Set the protocol to use
            #
            if len(self.gs.protocols) == 0:
                raise Error("No protocol installed")

            # TODO: Logic to go here to choose the right protocol based on the schedule
            if 'protocol' in metadata.keys():
                try:
                    self.gs.protocol = metadata['protocol']
                except Exception as e:
                    raise Error(
                        "Unknown protocol {} requested, pass cannot continue".
                        format(metadata['protocol']))
            else:
                log.info(
                    "No protocol has been specified, using default {}".format(
                        self.gs.protocols[0].name))
                try:
                    self.gs.protocol = self.gs.protocols[0]
                except Exception as e:
                    raise Error(
                        "Could not set default protocol. This error should really not be possible. {}: {}"
                        .format(e.__class__.__name__, e))

            # Make the pass metadata available to the protocol
            self.gs.protocol.sch_metadata = metadata

            #
            # Initialise
            #
            if self.schedule.passes[i].listen:
                log.debug("Listening pass, calling protocol.init_rx initiator")
                self.gs.protocol.init_rx()
            else:
                log.debug(
                    "Non-listening pass, calling protocol.init_rxtx initiator")
                self.gs.protocol.init_rxtx()

            #
            # This is a bit tricky but needs to be done this way so
            # that the action/transmit can be aborted.
            # What happens is that the method is run in a threadpool
            # and while we are waiting for the result we also monitor
            # for whether the station has stopped tracking or the _stop
            # flag has been set
            #
            #
            def action_thread(desc, *args, **kwargs):
                # this little wrapper function is just to make sure we log exceptions properly
                try:
                    self.gs.do_action(desc, *args, **kwargs)
                except Exception as e:
                    log.exception(
                        "{} performing action {}, {}, {}: '{}'".format(
                            e.__class__.__name__, desc, args, kwargs, e))
                    raise

            pool = ThreadPool(processes=1)

            #
            # Send all communications/actions
            #
            for comm in self.schedule.passes[i].comms:

                retry_cnt = -1
                while (retry_cnt < comm['retries']):

                    # This flag gets set if someone calls stop()
                    if self._stop:
                        return

                    # Make it possible to cancel schedule half-way through track
                    elif (not_tracking()):
                        log.error("Pass ended before comms finished")
                        return

                    if isinstance(comm, Action):

                        ret = pool.apply_async(lambda: action_thread(
                            comm['desc'], *comm['args'], **comm['kwargs']))
                        ret2 = wait_loop([ret.ready, not_tracking, stop])

                        if not_tracking in ret2 or stop in ret2:
                            log.error("do_action aborted")
                            return  # <--- the do_action may still be running, but will be dealt with by  the "finally" at the end of this function
                        elif not ret.successful():
                            log.error(
                                "Error performing action: %s. Trying again" %
                                (comm))
                            retry_cnt += 1
                            continue

                    else:

                        wait = -1 if comm[
                            'wait'] is False else Defaults.TX_REPLY_TIMEOUT

                        log.info("Transmitting %s" % (comm['hexstr']))

                        ret = pool.apply_async(lambda: self.gs.transmit(
                            comm['barray'], wait=wait))
                        ret2 = wait_loop([ret.ready, not_tracking, stop])

                        if not_tracking in ret2 or stop in ret2:
                            log.error("transmit aborted")
                            return  # <--- the do_action may still be running, but will be dealt with by  the "finally" at the end of this function
                        elif not ret.successful():
                            sleept = 10
                            log.error(
                                "Caught exception while transmitting. Waiting another %d sec, then continuing"
                                % (sleept))
                            wait_loop(
                                timeout=sleept
                            )  #<-- safe way to sleep. will terminate on global abort (but not for a normal stop, ok since its just a few seocncds)
                            retry_cnt += 1
                            continue

                    # if ok, break retry loop
                    break

            #
            # 4) End track,
            # (unless scheduler has been configured to follow track till its end)
            #
            if self.track_full_pass:
                log.info("Waiting for pass to finish")
                wait_loop([
                    stop, lambda: self.gs.state.state != self.gs.state.TRACKING
                ],
                          timeout=None,
                          dt=.5)
                return

            else:
                # Keep tracking for a bit since sometimes it seems data keeps coming
                log.info("Waiting up to %s before ending tracking" %
                         (self.schedule.buffertime))

                wait_loop([
                    stop, lambda: self.gs.state.state != self.gs.state.TRACKING
                ],
                          timeout=self.schedule.buffertime,
                          dt=.5)
                return

        except Exception as e:
            log.error(
                "Unhandled exception while executing pass: {}: {}".format(
                    e.__class__.__name__, e))
        finally:
            #
            # Turn off protocol/radio
            #
            try:
                self.gs.protocol.terminate()
                log.debug(
                    "execute_pass.finally reached and protocol.terminate() called successfully"
                )
            except Exception as e:
                log.error(
                    "execute_pass.finally reached but with error calling terminate: {}:{}"
                    .format(e.__class__.__name__, e))

            #
            # Stop tracking if its still doing so
            #
            try:
                self.gs.stop_track(block=True)
                log.debug(
                    "execute_pass.finally reached and groundstatio.stop_track() called successfully"
                )
            except Exception as e:
                log.error(
                    "execute_pass.finally reached but error calling groundstatio.stop_track(). {}: {}"
                    .format(e.__class__.__name__, e))