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())