class FrameMain(wx.Frame): def __init__(self): self._monitors = [] self._freqs = [] self._levels = numpy.zeros(BINS, dtype=numpy.float32) self._settings = Settings() self._filename = None self._receive = None self._dialogTimeline = None self._dialogSpectrum = None self._gps = None self._location = None self._ui = load_ui('FrameMain.xrc') handlerToolbar = XrcHandlerToolbar() self._ui.AddHandler(handlerToolbar) self._frame = self._ui.LoadFrame(None, 'FrameMain') self.__set_title() self._window = xrc.XRCCTRL(self._frame, 'window') self._status = xrc.XRCCTRL(self._frame, 'statusBar') self._toolbar = xrc.XRCCTRL(self._frame, 'PanelToolbar') self._sizerWindow = self._window.GetSizer() sdr = RtlSdr() gains = sdr.get_gains() gains = [float(gain) / 10. for gain in gains] sdr.close() self._toolbar.set_callbacks(self.__on_freq, self.__on_start, self.__on_rec, self.__on_stop, self.__on_add) self._toolbar.enable_start(True) self._toolbar.set_freq(self._settings.get_freq()) self._toolbar.set_gains(gains) self._toolbar.set_gain(self._settings.get_gain()) self.__add_monitors() self._server = Server(self._frame) self.__start_gps() self._menu = self._frame.GetMenuBar() idOpen = xrc.XRCID('menuOpen') self._menuOpen = self._menu.FindItemById(idOpen) self._frame.Bind(wx.EVT_MENU, self.__on_open, id=idOpen) idSave = xrc.XRCID('menuSave') self._menuSave = self._menu.FindItemById(idSave) self._frame.Bind(wx.EVT_MENU, self.__on_save, id=idSave) idSaveAs = xrc.XRCID('menuSaveAs') self._menuSaveAs = self._menu.FindItemById(idSaveAs) self._frame.Bind(wx.EVT_MENU, self.__on_save_as, id=idSaveAs) idClear = xrc.XRCID('menuClear') self._menuClear = self._menu.FindItemById(idClear) self._frame.Bind(wx.EVT_MENU, self.__on_clear, id=idClear) idGps = xrc.XRCID('menuGps') self._menuGps = self._menu.FindItemById(idGps) self._frame.Bind(wx.EVT_MENU, self.__on_gps, id=idGps) idTimeline = xrc.XRCID('menuTimeline') self._frame.Bind(wx.EVT_MENU, self.__on_timeline, id=idTimeline) self._menuTimeline = self._menu.FindItemById(idTimeline) idSpectrum = xrc.XRCID('menuSpectrum') self._frame.Bind(wx.EVT_MENU, self.__on_spectrum, id=idSpectrum) self._menuSpectrum = self._menu.FindItemById(idSpectrum) idExit = xrc.XRCID('menuExit') self._menuExit = self._menu.FindItemById(idExit) self._frame.Bind(wx.EVT_MENU, self.__on_exit, id=idExit) idAbout = xrc.XRCID('menuAbout') self._frame.Bind(wx.EVT_MENU, self.__on_about, id=idAbout) self._frame.Bind(EVT_TIMELINE_CLOSE, self.__on_timeline_close) self._frame.Bind(EVT_SPECTRUM_CLOSE, self.__on_spectrum_close) self._frame.Bind(wx.EVT_CLOSE, self.__on_exit) self._frame.Connect(-1, -1, EVENT_THREAD, self.__on_event) self._frame.Show() def __on_freq(self, freq): _l, freqs = psd(numpy.zeros(2, dtype=numpy.complex64), BINS, SAMPLE_RATE) freqs /= 1e6 freqs += freq self._freqs = freqs.tolist() def __on_start(self): self.__enable_controls(False) if self._receive is None: self._receive = Receive(self._frame, self._toolbar.get_freq(), self._toolbar.get_gain()) def __on_rec(self, recording): if recording: self.__on_start() for monitor in self._monitors: monitor.set_recording(recording) def __on_stop(self): self.__enable_controls(True) if self._receive is not None: self._receive.stop() self._receive = None for monitor in self._monitors: monitor.set_level(LEVEL_MIN, 0, None) if self._dialogSpectrum is not None: self._dialogSpectrum.clear_spectrum() def __on_add(self): monitor = PanelMonitor(self._window) monitor.set_callback(self.__on_del) monitor.set_freqs(self._freqs) self.__add_monitor(monitor) self._frame.Layout() def __on_del(self, monitor): index = self._monitors.index(monitor) self._sizerWindow.Hide(index) self._sizerWindow.Remove(index) self._frame.Layout() self._monitors.remove(monitor) self._toolbar.enable_freq(not len(self._monitors)) def __on_open(self, _event): if not self.__save_warning(): return defDir, defFile = '', '' if self._filename is not None: defDir, defFile = os.path.split(self._filename) dlg = wx.FileDialog(self._frame, 'Open File', defDir, defFile, 'rfmon files (*.rfmon)|*.rfmon', wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if dlg.ShowModal() == wx.ID_CANCEL: return self.open(dlg.GetPath()) def __on_save(self, _event): self.__save(False) def __on_save_as(self, _event): self.__save(True) def __on_clear(self, _event): resp = wx.MessageBox('Clear recorded data?', 'Warning', wx.OK | wx.CANCEL | wx.ICON_WARNING) if resp != wx.OK: return for monitor in self._monitors: monitor.clear_signals() def __on_gps(self, _event): dlg = DialogGps(self._frame, self._settings.get_gps()) if dlg.ShowModal() == wx.ID_OK: self.__stop_gps() self.__start_gps() def __on_timeline(self, event): if event.IsChecked() and self._dialogTimeline is None: self._dialogTimeline = DialogTimeline(self._frame) self._dialogTimeline.set_signals(self.__get_signals()) self._dialogTimeline.Show() elif self._dialogTimeline is not None: self._dialogTimeline.Destroy() self._dialogTimeline = None def __on_timeline_close(self, _event): self._menuTimeline.Check(False) self._dialogTimeline = None def __on_spectrum(self, event): if event.IsChecked() and self._dialogSpectrum is None: self._dialogSpectrum = DialogSpectrum(self._frame) self._dialogSpectrum.Show() elif self._dialogSpectrum is not None: self._dialogSpectrum.Destroy() self._dialogSpectrum = None def __on_spectrum_close(self, _event): self._menuSpectrum.Check(False) self._dialogSpectrum = None def __on_about(self, _event): dlg = DialogAbout(self._frame) dlg.ShowModal() def __on_exit(self, _event): if not self.__save_warning(): return self.__on_stop() if self._server is not None: self._server.stop() self.__stop_gps() self.__update_settings() self._settings.save() self._frame.Destroy() def __on_event(self, event): if event.type == Events.SCAN_ERROR: self.__on_scan_error(event.data) elif event.type == Events.SCAN_DATA: self.__on_scan_data(event.data) elif event.type == Events.SERVER_ERROR: self.__on_server_error(event.data) elif event.type == Events.GPS_ERROR: self._status.SetStatusText(event.data['msg'], 1) self.__restart_gps() elif event.type == Events.GPS_WARN: self._status.SetStatusText(event.data['msg'], 1) elif event.type == Events.GPS_TIMEOUT: self._status.SetStatusText(event.data['msg'], 1) self.__restart_gps() elif event.type == Events.GPS_LOC: self._location = event.data['loc'] loc = '{:9.5f}, {:9.5f}'.format(*self._location) self._status.SetStatusText(loc, 1) def __on_scan_error(self, event): wx.MessageBox(event['msg'], 'Error', wx.OK | wx.ICON_ERROR) self._toolbar.enable_start(True) def __on_scan_data(self, event): levels = numpy.log10(event['l']) levels *= 10 self._levels += levels self._levels /= 2. updated = False for monitor in self._monitors: freq = monitor.get_freq() if monitor.is_enabled(): index = numpy.where(freq == event['f'])[0] update = monitor.set_level(levels[index][0], event['timestamp'], self._location) if update: updated = True if self._server is not None: recording = format_recording(freq, update) self._server.send(recording) if self._dialogTimeline is not None and updated: self._dialogTimeline.set_signals(self.__get_signals()) if self._dialogSpectrum is not None: self._dialogSpectrum.set_spectrum(self._freqs, self._levels, event['timestamp']) def __on_server_error(self, event): sys.stderr.write(event['msg']) self._server = None def __set_title(self): title = APP_NAME if self._filename is not None: _head, tail = os.path.split(self._filename) title += ' - ' + tail self._frame.SetTitle(title) def __update_settings(self): self._settings.set_freq(self._toolbar.get_freq()) self._settings.set_gain(self._toolbar.get_gain()) self._settings.clear_monitors() for monitor in self._monitors: self._settings.add_monitor(monitor.is_enabled(), monitor.get_freq(), monitor.get_threshold(), monitor.get_signals()) def __save(self, prompt): if prompt or self._filename is None: defDir, defFile = '', '' if self._filename is not None: defDir, defFile = os.path.split(self._filename) dlg = wx.FileDialog(self._frame, 'Save File', defDir, defFile, 'rfmon files (*.rfmon)|*.rfmon', wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_CANCEL: return self._filename = dlg.GetPath() self.__update_settings() save_recordings(self._filename, self._settings) self.__set_title() for monitor in self._monitors: monitor.set_saved() def __save_warning(self): if not self.__is_saved(): resp = wx.MessageBox('Data is not saved, continue?', 'Warning', wx.OK | wx.CANCEL | wx.ICON_WARNING) if resp != wx.OK: return False return True def open(self, filename): load_recordings(filename, self._settings) self._filename = filename self.__set_title() self._toolbar.set_freq(self._settings.get_freq()) self.__clear_monitors() self.__add_monitors() if self._dialogTimeline is not None: self._dialogTimeline.set_signals(self.__get_signals()) def __enable_controls(self, enable): isSaved = self.__is_saved() self._menuOpen.Enable(enable) self._menuSave.Enable(enable) self._menuSaveAs.Enable(enable) self._menuClear.Enable(enable and isSaved) self._menuGps.Enable(enable) self._menuExit.Enable(enable) def __add_monitors(self): for monitor in self._settings.get_monitors(): panelMonitor = PanelMonitor(self._window) panelMonitor.set_callback(self.__on_del) panelMonitor.set_freqs(self._freqs) panelMonitor.set_enabled(monitor.enabled) panelMonitor.set_freq(monitor.freq) panelMonitor.set_threshold(monitor.threshold) panelMonitor.set_signals(monitor.signals) self.__add_monitor(panelMonitor) self._frame.Layout() def __add_monitor(self, monitor): self._toolbar.enable_freq(False) self._monitors.append(monitor) self._sizerWindow.Add(monitor, 0, wx.ALL | wx.EXPAND, 5) def __clear_monitors(self): for _i in range(len(self._monitors)): self._sizerWindow.Hide(0) self._sizerWindow.Remove(0) self._frame.Layout() self._monitors = [] self._toolbar.enable_freq(True) def __get_signals(self): return [(monitor.get_freq(), monitor.get_signals()) for monitor in self._monitors] def __is_saved(self): for monitor in self._monitors: if not monitor.get_saved(): return False return True def __start_gps(self): if self._gps is None and self._settings.get_gps().enabled: self._status.SetStatusText('Staring GPS...', 1) self._gps = Gps(self._frame, self._settings.get_gps()) def __stop_gps(self): if self._gps is not None: self._gps.stop() self._gps = None def __restart_gps(self): self.__stop_gps() wx.CallLater(GPS_RETRY * 1000, self.__start_gps)
class Cli(wx.EvtHandler): def __init__(self, args): wx.EvtHandler.__init__(self) self._monitors = [] self._freqs = [] self._location = None self._settings = Settings() self._filename = args.file self._gpsPort = args.port self._gpsBaud = args.baud self._json = args.json self._receive = None self._cancel = False self._queue = Queue.Queue() self.__open() self.__add_monitors() self._signal = signal.signal(signal.SIGINT, self.__on_exit) self._server = Server(self._queue) self._gps = None self.__start_gps() self.__start() while not self._cancel: if not self._queue.empty(): self.__on_event() self.__std_out('Exiting') self._receive.stop() self.__stop_gps() if self._server is not None: self._server.stop() if not self.__is_saved(): self.__std_out('Saving') self.__save() def __open(self): load_recordings(self._filename, self._settings) def __save(self): save_recordings(self._filename, self._settings) def __is_saved(self): for monitor in self._monitors: if not monitor.get_saved(): return False return True def __add_monitors(self): freqs = [] for monitor in self._settings.get_monitors(): freq = monitor.freq freqs.append(freq) cliMonitor = CliMonitor(monitor.freq, monitor.threshold, monitor.enabled, monitor.signals) self._monitors.append(cliMonitor) freqs = map(str, freqs) self.__std_out('Monitors:') self.__std_out(', '.join(freqs) + 'MHz\n') def __start_gps(self): gpsDevice = GpsDevice() if self._gpsPort is not None: gpsDevice.port = self._gpsPort if self._gpsBaud is not None: gpsDevice.baud = self._gpsBaud if self._gpsPort is not None: self._gps = Gps(self._queue, gpsDevice) def __stop_gps(self): if self._gps is not None: self._gps.stop() def __restart_gps(self): timer = Timer(GPS_RETRY, self.__start_gps) timer.start() def __start(self): self.__std_out('Monitoring') self._receive = Receive(self._queue, self._settings.get_freq(), self._settings.get_gain()) def __std_out(self, message): if not self._json: sys.stdout.write(message + '\n') def __std_err(self, message): if not self._json: sys.stderr.write(message + '\n') def __on_exit(self, _signal=None, _frame=None): signal.signal(signal.SIGINT, self._signal) self._cancel = True def __on_event(self): event = self._queue.get() if event.type == Events.SCAN_ERROR: self.__on_scan_error(event.data) elif event.type == Events.SCAN_DATA: self.__on_scan_data(event.data) elif event.type == Events.SERVER_ERROR: self.__on_server_error(event.data) elif event.type == Events.GPS_ERROR: self.__std_err(event.data['msg']) self.__restart_gps() elif event.type == Events.GPS_WARN: self.__std_err(event.data['msg']) elif event.type == Events.GPS_TIMEOUT: self.__std_err(event.data['msg']) self.__restart_gps() elif event.type == Events.GPS_LOC: self._location = event.data['loc'] else: time.sleep(0.01) def __on_scan_error(self, event): self.__std_err(event['msg']) exit(1) def __on_scan_data(self, event): levels = numpy.log10(event['l']) levels *= 10 for monitor in self._monitors: freq = monitor.get_freq() if monitor.is_enabled(): index = numpy.where(freq == event['f'])[0] update = monitor.set_level(levels[index][0], event['timestamp'], self._location) if update: recording = format_recording(freq, update) if self._server is not None: self._server.send(recording) if self._json: sys.stdout.write(recording + '\n') def __on_server_error(self, event): self.__std_err(event['msg']) self._server = None