def __on_start(self, _event):
     if not self.threadLocation:
         self.buttonStart.Disable()
         self.buttonStop.Enable()
         self.textRaw.SetValue('')
         self.__add_raw('Starting...')
         self.threadLocation = ThreadLocation(self.queue, self.device,
                                              raw=True)
예제 #2
0
    def __init__(self, args):
        start = args.start
        end = args.end
        sweeps = args.sweeps
        gain = args.gain
        dwell = args.dwell
        nfft = args.fft
        lo = args.lo
        index = args.index
        remote = args.remote
        directory, filename = os.path.split(args.file)
        _null, ext = os.path.splitext(args.file)

        self.lock = threading.Lock()

        self.stepsTotal = 0
        self.steps = 0

        self.spectrum = OrderedDict()
        self.locations = OrderedDict()
        self.settings = Settings(load=False)

        self.queueNotify = Queue()
        self.queueScan = Queue()
        self.queueLocation = Queue()

        self.threadLocation = None

        error = None

        if end <= start:
            error = "Start should be lower than end"
        elif dwell <= 0:
            error = "Dwell should be positive"
        elif dwell > max(get_dwells()[1::2]):
            error = "Dwell should equal lower than {}s".format(max(get_dwells()[1::2]))
        elif nfft <= 0:
            error = "FFT bins should be positive"
        elif ext != ".rfs" and File.get_type_index(ext) == -1:
            error = "File extension should be "
            error += File.get_type_pretty(File.Types.SAVE)
            error += File.get_type_pretty(File.Types.PLOT)
        else:
            device = DeviceRTL()
            if remote is None:
                self.settings.devicesRtl = get_devices_rtl()
                count = len(self.settings.devicesRtl)
                if index > count - 1:
                    error = "Device not found ({} devices in total):\n".format(count)
                    for device in self.settings.devicesRtl:
                        error += "\t{}: {}\n".format(device.indexRtl,
                                                     device.name)
            else:
                device.isDevice = False
                url = urlparse('//' + remote)
                if url.hostname is not None:
                    device.server = url.hostname
                else:
                    error = "Invalid hostname"
                if url.port is not None:
                    device.port = url.port
                else:
                    device.port = 1234
                self.settings.devicesRtl.append(device)
                index = len(self.settings.devicesRtl) - 1

            if args.conf is not None:
                if os.path.exists(args.conf):
                    error = self.settings.load_conf(args.conf)
                    if error is not None:
                        error = 'GPS configuration - ' + error
                else:
                    error = 'Cannot find {}'.format(args.conf)

            if end - 1 < start:
                end = start + 1
            if remote is None:
                if len(self.settings.devicesRtl):
                    gain = nearest(gain, self.settings.devicesRtl[index].gains)
                else:
                    error = 'No devices found'

        if error is not None:
            print("Error: {}".format(error))
            exit(1)

        self.settings.start = start
        self.settings.stop = end
        self.settings.dwell = calc_real_dwell(dwell)
        self.settings.scanDelay = args.delay
        self.settings.nfft = nfft
        self.settings.devicesRtl[index].gain = gain
        self.settings.devicesRtl[index].lo = lo

        print("{} - {}MHz".format(start, end))
        print("{} Sweeps".format(sweeps))
        print("{}dB Gain".format(gain))
        print("{}s Dwell".format(self.settings.dwell))
        print("{} FFT points".format(nfft))
        print("{}MHz LO".format(lo))
        if remote is not None:
            print(remote)
        else:
            print(self.settings.devicesRtl[index].name)

        if len(self.settings.devicesGps):
            print('Using GPS configuration \'{}\''.format(self.settings.devicesGps[0].name))
            self.threadLocation = ThreadLocation(self.queueLocation,
                                                 self.settings.devicesGps[0])
            if not self.__gps_wait():
                self.__gps_stop()
                exit(1)

        self.__scan(sweeps, self.settings, index)

        fullName = os.path.join(directory, filename)
        if ext == ".rfs":
            scanInfo = ScanInfo()
            scanInfo.set_from_settings(self.settings)

            save_plot(fullName, scanInfo, self.spectrum, self.locations)
        else:
            exportType = File.get_type_index(ext)
            export_plot(fullName, exportType, self.spectrum)

        self.__gps_stop()
        print("Done")
예제 #3
0
class Cli:
    def __init__(self, args):
        start = args.start
        end = args.end
        sweeps = args.sweeps
        gain = args.gain
        dwell = args.dwell
        nfft = args.fft
        lo = args.lo
        index = args.index
        remote = args.remote
        directory, filename = os.path.split(args.file)
        _null, ext = os.path.splitext(args.file)

        self.lock = threading.Lock()

        self.stepsTotal = 0
        self.steps = 0

        self.spectrum = OrderedDict()
        self.locations = OrderedDict()
        self.settings = Settings(load=False)

        self.queueNotify = Queue()
        self.queueScan = Queue()
        self.queueLocation = Queue()

        self.threadLocation = None

        error = None

        if end <= start:
            error = "Start should be lower than end"
        elif dwell <= 0:
            error = "Dwell should be positive"
        elif dwell > max(get_dwells()[1::2]):
            error = "Dwell should equal lower than {}s".format(max(get_dwells()[1::2]))
        elif nfft <= 0:
            error = "FFT bins should be positive"
        elif ext != ".rfs" and File.get_type_index(ext) == -1:
            error = "File extension should be "
            error += File.get_type_pretty(File.Types.SAVE)
            error += File.get_type_pretty(File.Types.PLOT)
        else:
            device = DeviceRTL()
            if remote is None:
                self.settings.devicesRtl = get_devices_rtl()
                count = len(self.settings.devicesRtl)
                if index > count - 1:
                    error = "Device not found ({} devices in total):\n".format(count)
                    for device in self.settings.devicesRtl:
                        error += "\t{}: {}\n".format(device.indexRtl,
                                                     device.name)
            else:
                device.isDevice = False
                url = urlparse('//' + remote)
                if url.hostname is not None:
                    device.server = url.hostname
                else:
                    error = "Invalid hostname"
                if url.port is not None:
                    device.port = url.port
                else:
                    device.port = 1234
                self.settings.devicesRtl.append(device)
                index = len(self.settings.devicesRtl) - 1

            if args.conf is not None:
                if os.path.exists(args.conf):
                    error = self.settings.load_conf(args.conf)
                    if error is not None:
                        error = 'GPS configuration - ' + error
                else:
                    error = 'Cannot find {}'.format(args.conf)

            if end - 1 < start:
                end = start + 1
            if remote is None:
                if len(self.settings.devicesRtl):
                    gain = nearest(gain, self.settings.devicesRtl[index].gains)
                else:
                    error = 'No devices found'

        if error is not None:
            print("Error: {}".format(error))
            exit(1)

        self.settings.start = start
        self.settings.stop = end
        self.settings.dwell = calc_real_dwell(dwell)
        self.settings.scanDelay = args.delay
        self.settings.nfft = nfft
        self.settings.devicesRtl[index].gain = gain
        self.settings.devicesRtl[index].lo = lo

        print("{} - {}MHz".format(start, end))
        print("{} Sweeps".format(sweeps))
        print("{}dB Gain".format(gain))
        print("{}s Dwell".format(self.settings.dwell))
        print("{} FFT points".format(nfft))
        print("{}MHz LO".format(lo))
        if remote is not None:
            print(remote)
        else:
            print(self.settings.devicesRtl[index].name)

        if len(self.settings.devicesGps):
            print('Using GPS configuration \'{}\''.format(self.settings.devicesGps[0].name))
            self.threadLocation = ThreadLocation(self.queueLocation,
                                                 self.settings.devicesGps[0])
            if not self.__gps_wait():
                self.__gps_stop()
                exit(1)

        self.__scan(sweeps, self.settings, index)

        fullName = os.path.join(directory, filename)
        if ext == ".rfs":
            scanInfo = ScanInfo()
            scanInfo.set_from_settings(self.settings)

            save_plot(fullName, scanInfo, self.spectrum, self.locations)
        else:
            exportType = File.get_type_index(ext)
            export_plot(fullName, exportType, self.spectrum)

        self.__gps_stop()
        print("Done")

    def __gps_wait(self):
        print('\nWaiting for GPS fix: {}'.format(self.settings.devicesGps[0].get_desc()))

        while True:
            if not self.queueLocation.empty():
                status = self.__process_event(self.queueLocation)
                if status == Event.LOC:
                    return True
                elif status == Event.LOC_ERR:
                    return False

    def __gps_stop(self):
        if self.threadLocation and self.threadLocation.is_alive():
            self.threadLocation.stop()

    def __scan(self, sweeps, settings, index):
        samples = settings.dwell * SAMPLE_RATE
        samples = next_2_to_pow(int(samples))

        for sweep in range(0, sweeps):
            print('\nSweep {}:'.format(sweep + 1))
            threadScan = ThreadScan(self.queueNotify, self.queueScan, None,
                                    settings, index, samples, False)
            while threadScan.is_alive() or self.steps > 0:
                if not self.queueNotify.empty():
                    self.__process_event(self.queueNotify)
                if not self.queueLocation.empty():
                    self.__process_event(self.queueLocation)
            if self.settings.scanDelay > 0 and sweep < sweeps - 1:
                print('\nDelaying {}s'.format(self.settings.scanDelay))
                time.sleep(self.settings.scanDelay)
            threadScan.rtl_close()
            print("")
        print("")

    def __process_event(self, queue):
        event = queue.get()
        status = event.data.get_status()
        arg1 = event.data.get_arg1()
        arg2 = event.data.get_arg2()

        if status == Event.STARTING:
            print("Starting")
        elif status == Event.STEPS:
            self.stepsTotal = (arg1 + 1) * 2
            self.steps = self.stepsTotal
        elif status == Event.INFO:
            if arg2 != -1:
                self.settings.devicesRtl[self.settings.indexRtl].tuner = arg2
        elif status == Event.DATA:
            cal = self.settings.devicesRtl[self.settings.indexRtl].calibration
            levelOff = self.settings.devicesRtl[self.settings.indexRtl].levelOff
            freq, scan = self.queueScan.get()
            process = ThreadProcess(self.queueNotify,
                                    freq, scan, cal, levelOff,
                                    self.settings.nfft,
                                    self.settings.overlap,
                                    self.settings.winFunc)
            process.start()
            self.__progress()
        elif status == Event.ERROR:
            print("Error: {}".format(arg2))
            exit(1)
        elif status == Event.PROCESSED:
            offset = self.settings.devicesRtl[self.settings.indexRtl].offset
            Thread(target=update_spectrum, name='Update',
                   args=(self.queueNotify, self.lock,
                         self.settings.start,
                         self.settings.stop,
                         arg1,
                         offset,
                         self.spectrum,
                         not self.settings.retainScans,
                         False)).start()
        elif status == Event.UPDATED:
            self.__progress()
        elif status == Event.LOC:
            if len(self.spectrum) > 0:
                self.locations[max(self.spectrum)] = (arg2[0],
                                                      arg2[1],
                                                      arg2[2])
        elif status == Event.LOC_ERR:
            print('Error: {}'.format(arg2))
            exit(1)

        return status

    def __progress(self):
        self.steps -= 1
        comp = (self.stepsTotal - self.steps) * 100 / self.stepsTotal
        sys.stdout.write("\r{0:.1f}%".format(comp))
class DialogGPSTest(wx.Dialog):
    POLL = 500

    def __init__(self, parent, device):
        self.device = device
        self.threadLocation = None
        self.raw = ''

        wx.Dialog.__init__(self, parent=parent, title='GPS Test')

        textLat = wx.StaticText(self, label='Longitude')
        self.textLat = wx.TextCtrl(self, style=wx.TE_READONLY)
        textLon = wx.StaticText(self, label='Latitude')
        self.textLon = wx.TextCtrl(self, style=wx.TE_READONLY)
        textAlt = wx.StaticText(self, label='Altitude')
        self.textAlt = wx.TextCtrl(self, style=wx.TE_READONLY)
        textSats = wx.StaticText(self, label='Satellites')
        self.textSats = wx.TextCtrl(self, style=wx.TE_READONLY)
        textRaw = wx.StaticText(self, label='Raw output')
        self.textRaw = wx.TextCtrl(self,
                                   style=wx.TE_MULTILINE | wx.TE_READONLY)

        textLevel = wx.StaticText(self, label='Level')
        self.satLevel = SatLevel(self)

        self.buttonStart = wx.Button(self, label='Start')
        self.Bind(wx.EVT_BUTTON, self.__on_start, self.buttonStart)
        self.buttonStop = wx.Button(self, label='Stop')
        self.Bind(wx.EVT_BUTTON, self.__on_stop, self.buttonStop)
        self.buttonStop.Disable()

        buttonOk = wx.Button(self, wx.ID_OK)
        self.Bind(wx.EVT_BUTTON, self.__on_ok, buttonOk)

        grid = wx.GridBagSizer(10, 10)

        grid.Add(textLat, pos=(0, 0), flag=wx.ALL, border=5)
        grid.Add(self.textLat, pos=(0, 1), span=(1, 2), flag=wx.ALL, border=5)
        grid.Add(textLon, pos=(1, 0), flag=wx.ALL, border=5)
        grid.Add(self.textLon, pos=(1, 1), span=(1, 2), flag=wx.ALL, border=5)
        grid.Add(textAlt, pos=(2, 0), flag=wx.ALL, border=5)
        grid.Add(self.textAlt, pos=(2, 1), span=(1, 2), flag=wx.ALL, border=5)
        grid.Add(textSats, pos=(3, 0), flag=wx.ALL, border=5)
        grid.Add(self.textSats, pos=(3, 1), span=(1, 2), flag=wx.ALL, border=5)
        grid.Add(textLevel, pos=(0, 3), flag=wx.ALL, border=5)
        grid.Add(self.satLevel, pos=(1, 3), span=(3, 2), flag=wx.ALL, border=5)
        grid.Add(textRaw, pos=(4, 0), flag=wx.ALL, border=5)
        grid.Add(self.textRaw, pos=(5, 0), span=(5, 5),
                 flag=wx.ALL | wx.EXPAND, border=5)
        grid.Add(self.buttonStart, pos=(10, 2), flag=wx.ALL, border=5)
        grid.Add(self.buttonStop, pos=(10, 3), flag=wx.ALL | wx.ALIGN_RIGHT,
                 border=5)
        grid.Add(buttonOk, pos=(11, 4), flag=wx.ALL | wx.ALIGN_RIGHT,
                 border=5)

        self.SetSizerAndFit(grid)

        self.queue = Queue.Queue()
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.__on_timer, self.timer)
        self.timer.Start(self.POLL)

    def __on_start(self, _event):
        if not self.threadLocation:
            self.buttonStart.Disable()
            self.buttonStop.Enable()
            self.textRaw.SetValue('')
            self.__add_raw('Starting...')
            self.threadLocation = ThreadLocation(self.queue, self.device,
                                                 raw=True)

    def __on_stop(self, _event):
        if self.threadLocation and self.threadLocation.isAlive():
            self.__add_raw('Stopping...')
            self.threadLocation.stop()
            self.threadLocation.join()
        self.threadLocation = None
        self.satLevel.clear_sats()
        self.textLat.SetValue('')
        self.textLon.SetValue('')
        self.textAlt.SetValue('')
        self.textSats.SetValue('')
        self.buttonStart.Enable()
        self.buttonStop.Disable()

    def __on_ok(self, _event):
        self.__on_stop(None)
        self.EndModal(wx.ID_OK)

    def __on_timer(self, _event):
        self.timer.Stop()
        while not self.queue.empty():
            event = self.queue.get()
            status = event.data.get_status()
            loc = event.data.get_arg2()

            if status == Event.LOC:
                if loc[0] is not None:
                    text = '{:.5f}'.format(loc[0])
                else:
                    text = ''
                self.textLon.SetValue(text)
                if loc[1] is not None:
                    text = '{:.5f}'.format(loc[1])
                else:
                    text = ''
                self.textLat.SetValue(text)
                if loc[2] is not None:
                    text = '{:.1f}'.format(loc[2])
                else:
                    text = ''
                self.textAlt.SetValue(text)
            elif status == Event.LOC_SAT:
                self.satLevel.set_sats(loc)
                used = sum(1 for sat in loc.values() if sat[1])
                self.textSats.SetLabel('{}/{}'.format(used, len(loc)))
            elif status == Event.LOC_ERR:
                self.__on_stop(None)
                self.__add_raw('{}'.format(loc))
            elif status == Event.LOC_RAW:
                self.__add_raw(loc)
        self.timer.Start(self.POLL)

    def __add_raw(self, text):
        text = text.replace('\n', '')
        text = text.replace('\r', '')
        terminal = self.textRaw.GetValue().split('\n')
        terminal.append(text)
        while len(terminal) > 100:
            terminal.pop(0)
        self.textRaw.SetValue('\n'.join(terminal))
        self.textRaw.ScrollPages(self.textRaw.GetNumberOfLines())