Compare commits

..

1 Commits

Author SHA1 Message Date
Ezra Taimuty-Loomis 64da45fdde Replaced UI file parsing with generated code 2021-02-26 22:00:08 -05:00
8 changed files with 2099 additions and 105 deletions

View File

@ -23,6 +23,7 @@ A license hasn't been selected yet, though it's likely to be GPL - have to make
- AM demodulation
- Run-time manipulation of scan database and config
- Temporary channel lockout
- SDR configuration
#### Long term:
- P25 trunking
- DMR trunking
@ -74,21 +75,21 @@ Depending on your preferred build system
There are three options available for audio output: PulseAudio, ALSA, JACK, and OSS. By default ALSA is the selected library. Your preference can be set by running one of the following commands from the `build` directory:
cmake .. -DUSE_AUDIO_PULSE=ON
cmake .. -DUSE_AUDIO_ALSA=ON
cmake .. -DUSE_AUDIO_JACK=ON
cmake ../src -DUSE_AUDIO_PULSE=ON
cmake ../src -DUSE_AUDIO_ALSA=ON
cmake ../src -DUSE_AUDIO_JACK=ON
Do note that PulseAudio uses significantly more CPU than ALSA when streaming PiScan audio.
Additionally, some versions of liquid, particularly `libliquid2d` and `libliquid-dev` versions `1.3.2` and greater, have a different API, resulting in build errors in the "Modem" files of the `cubic` module. If that happens, try running this from `build`:
Additionally, some versions of liquid, particularly `libliquid-dev` versions `1.3.2` and greater, have a different API, resulting in build errors in the "Modem" files of the `cubic` module. If that happens, try running this from `build`:
cmake .. -DLIQUID_API_OLD=OFF
cmake ../src -DLIQUID_API_OLD=OFF
### Building
Once the environment is properly configured, `cd` into `build` and build the LiveMedia library:
make live555
If the build fails: If you are building in a shared folder in a VM on a Windows host, you must download and extract the Live sourcefiles manually into `src/external/live` and run the command below before trying again. This is due to Windows not playing nicely with permissions and symbolic links
cmake .. -DHGFS=ON
cmake ../src -DHGFS=ON
Now you can build PiScan:
make all
@ -97,20 +98,13 @@ Alternatively, you can build the binaries individually if you don't need all of
make piscan_server # main program
make piscan_hpdconv # tool to convert Uniden Sentinel files to PiScan files
Once the build is complete, you can run the install script:
sudo make install
Note: install must be re-run if the project is rebuilt
### Running
PiScan can now be run with the command:
For now, you have to be in the `build` directory to run the program. In the future there will be an install command to eliminate the need for this.
You can now run PiScan from the command line:
piscan_server [args]
./src/piscan_server
See **Usage** for more information on command arguments and setting up the data files
Alternatively, if you prefer not to use `make install` you can run it locally from the `build` directory with the command:
./src/piscan_server [args]
## Usage
### Command Arguments
@ -125,18 +119,6 @@ All data used by PiScan is stored in its working directory (this is the `data` d
- `systems.json` contains the scan database - more on what that looks like below
On the first run of PiScan, these files likely won't exist. It will continue running with default parameters, and a config and state file will be generated with these defaults when the program ends.
If there is no scan file, PiScan cannot scan so it will instead hold at 100MHz. It will not allow the user to scan, but will allow manual frequency tuning.
#### SDR configuration
PiScan allows for configuring specific RTL dongles to run with it. By default, it doesn't have any pre-configured SDR's, so it will select the first available device and save it to the config file. One it's in the config file it will be given a rank (for specifying the order PiScan chooses from configured devies) and a descriptor, which contains the device name and serial number. There, the dongle's PPM correction and preferred sample rate can be set. The format of each device config is as such:
{
"rank": "0",
"descriptor": "Generic RTL2832U OEM :: 00000001",
"driver": "rtlsdr",
"ppm_correction": "0",
"sample_rate": "2048000"
}
#### Scan Database File
`systems.json` MUST adhere to this format (minus the comments) for PiScan to read it correctly. Use the sample file in `data/defaults` as a starting point for your database if writing it manually.

View File

@ -12,6 +12,7 @@ from threading import Thread
from time import sleep
import ui_scan_client
import audio_manager
import common
import constants
@ -34,13 +35,9 @@ class PiScanClient(QWidget, common.AppInterface):
def __init__(self, parent=None, address=None, port=None, use_audio=False, rtsp_port=None):
super(PiScanClient, self).__init__(parent)
common.setInstance(self)
ui_file = 'scan_client.ui'
ui_file = QFile(ui_file)
ui_file.open(QFile.ReadOnly)
loader = QUiLoader()
self.window = loader.load(ui_file)
ui_file.close()
self.window = ui_scan_client.Ui_Form()
self.window.setupUi(self)
self.parentWindow = parent
#layout = QGridLayout(self)
@ -53,7 +50,7 @@ class PiScanClient(QWidget, common.AppInterface):
self.scanner = scanner.Scanner(self.window)
self.dialogs = dialogs.Dialogs(self.window)
self.contextStack = self.window.findChild(QStackedWidget, 'contextStack')
self.contextStack = self.window.contextStack
#self.setWindowMode(common.WindowMode.CONNECT)
self.showConnectDialog()
#self.setWindowMode(common.WindowMode.SCANNER)
@ -280,12 +277,11 @@ class HostWindow(QtWidgets.QMainWindow):
form = PiScanClient(self, address, port, use_audio, rtsp_port)
mainWidget = form.mainWidget()
self.setPalette(mainWidget.palette())
self.setGeometry(mainWidget.geometry())
self.setWindowTitle(mainWidget.windowTitle())
self.setPalette(form.palette())
self.setGeometry(form.geometry())
self.setWindowTitle(form.windowTitle())
self.setCentralWidget(mainWidget)
self.setCentralWidget(form)
#self.actionQuit.triggered.connect(self.closeEvent)
#self.show()

View File

@ -12,18 +12,18 @@ import constants
class ConnectDialog:
def __init__(self, parentWindow, address=None, port=None, use_audio=False, rtsp_port=None):
self.widget = parentWindow.findChild(QWidget, 'connectPage')
self.errorLabel = parentWindow.findChild(QLabel, 'connect_errorLabel')
self.confirmButton = parentWindow.findChild(QPushButton, 'connect_confirmButton')
self.connectIndicator = parentWindow.findChild(QLabel, 'connect_indicator')
self.hostLineEdit = parentWindow.findChild(QLineEdit, 'connect_hostnameLineEdit')
self.portLineEdit = parentWindow.findChild(QLineEdit, 'connect_portLineEdit')
self.logo = parentWindow.findChild(QLabel, 'connect_logoImage')
self.hostLabel = parentWindow.findChild(QLabel, 'hostLabel')
self.portLabel = parentWindow.findChild(QLabel, 'hostPortLabel')
self.audioCheckBox = parentWindow.findChild(QCheckBox, 'connect_audioCheckBox')
self.rtspPortPanel = parentWindow.findChild(QWidget, 'connect_rtspPortPanel')
self.rtspPortLineEdit = parentWindow.findChild(QLineEdit, 'connect_rtspPortLineEdit')
self.widget = parentWindow.connectPage
self.errorLabel = parentWindow.connect_errorLabel
self.confirmButton = parentWindow.connect_confirmButton
self.connectIndicator = parentWindow.connect_indicator
self.hostLineEdit = parentWindow.connect_hostnameLineEdit
self.portLineEdit = parentWindow.connect_portLineEdit
self.logo = parentWindow.connect_logoImage
self.hostLabel = parentWindow.hostLabel
self.portLabel = parentWindow.hostPortLabel
self.audioCheckBox = parentWindow.connect_audioCheckBox
self.rtspPortPanel = parentWindow.connect_rtspPortPanel
self.rtspPortLineEdit = parentWindow.connect_rtspPortLineEdit
self.logo.setPixmap(QPixmap("resources/icon-256.png"))
self.logo.setVisible(False)

View File

@ -10,11 +10,11 @@ class Dialogs:
dialogStack = deque()
def __init__(self, parent):
self.widget = parent.findChild(QWidget, 'dialogsPage')
self.header = parent.findChild(QWidget, 'dialogHeader')
self.backButton = parent.findChild(QPushButton, 'dialog_backButton')
self.titleLabel = parent.findChild(QLabel, 'dialog_titleLabel')
self.dialogStackWidget = parent.findChild(QStackedWidget, 'dialogsStack')
self.widget = parent.dialogsPage
self.header = parent.dialogHeader
self.backButton = parent.dialog_backButton
self.titleLabel = parent.dialog_titleLabel
self.dialogStackWidget = parent.dialogsStack
self.backButton.clicked.connect(self.dialogReturn)
self.dialogStackWidget.currentChanged.connect(self.updateTitle)
@ -47,10 +47,10 @@ class Dialogs:
class ManualEntry:
def __init__(self, parentWindow, dialogHost):
self.widget = parentWindow.findChild(QWidget, 'manualEntryDialog')
self.confirmButton = parentWindow.findChild(QPushButton, 'manual_confirmButton')
self.freqLineEdit = parentWindow.findChild(QLineEdit, 'manual_freqLineEdit')
self.modulationCombo = parentWindow.findChild(QComboBox, 'manual_modulationCombo')
self.widget = parentWindow.manualEntryDialog
self.confirmButton = parentWindow.manual_confirmButton
self.freqLineEdit = parentWindow.manual_freqLineEdit
self.modulationCombo = parentWindow.manual_modulationCombo
self.host = dialogHost
self.confirmButton.clicked.connect(self.onConfirm)
@ -68,12 +68,12 @@ class Dialogs:
class EditEntry:
def __init__(self, parent):
self.widget = parent.findChild(QWidget, 'editEntryDialog')
self.codeLineEdit = parent.findChild(QLineEdit, 'entry_codeLineEdit')
self.delayLineEdit = parent.findChild(QLineEdit, 'entry_delayLineEdit')
self.freqLineEdit = parent.findChild(QLineEdit, 'entry_freqLineEdit')
self.lockoutCheckbox = parent.findChild(QCheckBox, 'entry_lockoutCheckbox')
self.modulationCombo = parent.findChild(QComboBox, 'entry_modulationCombo')
self.systemCombo = parent.findChild(QComboBox, 'entry_systemCombo')
self.tagLineEdit = parent.findChild(QLineEdit, 'entry_tagLineEdit')
self.widget = parent.editEntryDialog
self.codeLineEdit = parent.entry_codeLineEdit
self.delayLineEdit = parent.entry_delayLineEdit
self.freqLineEdit = parent.entry_freqLineEdit
self.lockoutCheckbox = parent.entry_lockoutCheckbox
self.modulationCombo = parent.entry_modulationCombo
self.systemCombo = parent.entry_systemCombo
self.tagLineEdit = parent.entry_tagLineEdit

View File

@ -4917,7 +4917,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>179</width>
<width>443</width>
<height>223</height>
</rect>
</property>

View File

@ -17,43 +17,41 @@ class Scanner:
squelchFromContext = False
def __init__(self, parentWindow):
self.widget = parentWindow.findChild(QWidget, 'scannerPage')
self.contextStack = parentWindow.findChild(QStackedWidget, 'scanContextStack')
self.holdPage = parentWindow.findChild(QWidget, 'scanner_holdPage')
self.scanPage = parentWindow.findChild(QWidget, 'scanner_scanPage')
self.entryTagLabel = parentWindow.findChild(QLabel, 'scanner_entryTagLabel')
self.frequencyLabel = parentWindow.findChild(QLabel, 'scanner_frequencyLabel')
self.modulationLabel = parentWindow.findChild(QLabel, 'scanner_modulationLabel')
self.systemTagLabel = parentWindow.findChild(QLabel, 'scanner_systemTagLabel')
self.entryNumLabel = parentWindow.findChild(QLabel, 'scanner_entryNumLabel')
self.delayLabel = parentWindow.findChild(QLabel, 'scanner_delayLabel')
self.lockoutDurationLabel = parentWindow.findChild(QLabel, 'scanner_lockoutDurationLabel')
self.scanModeLabel = parentWindow.findChild(QLabel, 'scanner_scanModeLabel')
self.lockoutDurationButton = parentWindow.findChild(QPushButton, 'scanner_lockoutDurationButton')
self.scanIndicator = parentWindow.findChild(QLabel, 'scanner_scanIndicator')
self.gainSlider = parentWindow.findChild(QSlider, 'scanner_gainSlider')
##self.gainLabel = parentWindow.findChild(QLabel, 'scanner_gainLabel')
self.sigStrengthBar = parentWindow.findChild(QProgressBar, 'scanner_sigStrengthBar')
self.squelchSlider = parentWindow.findChild(QSlider, 'scanner_squelchSlider')
##self.squelchLabel = parentWindow.findChild(QLabel, 'scanner_squelchLabel')
self.fnButtonsWidget = parentWindow.findChild(QWidget, 'scanner_fnButtonsWidget')
self.fnButton1 = parentWindow.findChild(QPushButton, 'scanner_fnButton1')
self.fnButton2 = parentWindow.findChild(QPushButton, 'scanner_fnButton2')
self.fnButton3 = parentWindow.findChild(QPushButton, 'scanner_fnButton3')
self.fnButton4 = parentWindow.findChild(QPushButton, 'scanner_fnButton4')
self.widget = parentWindow.scannerPage
self.contextStack = parentWindow.scanContextStack
self.holdPage = parentWindow.scanner_holdPage
self.scanPage = parentWindow.scanner_scanPage
self.entryTagLabel = parentWindow.scanner_entryTagLabel
self.frequencyLabel = parentWindow.scanner_frequencyLabel
self.modulationLabel = parentWindow.scanner_modulationLabel
self.systemTagLabel = parentWindow.scanner_systemTagLabel
self.entryNumLabel = parentWindow.scanner_entryNumLabel
self.delayLabel = parentWindow.scanner_delayLabel
self.lockoutDurationLabel = parentWindow.scanner_lockoutDurationLabel
self.scanModeLabel = parentWindow.scanner_scanModeLabel
self.lockoutDurationButton = parentWindow.scanner_lockoutDurationButton
self.scanIndicator = parentWindow.scanner_scanIndicator
self.gainSlider = parentWindow.scanner_gainSlider
self.sigStrengthBar = parentWindow.scanner_sigStrengthBar
self.squelchSlider = parentWindow.scanner_squelchSlider
self.fnButtonsWidget = parentWindow.scanner_fnButtonsWidget
self.fnButton1 = parentWindow.scanner_fnButton1
self.fnButton2 = parentWindow.scanner_fnButton2
self.fnButton3 = parentWindow.scanner_fnButton3
self.fnButton4 = parentWindow.scanner_fnButton4
self.sidebarToggleButton = parentWindow.findChild(QToolButton, 'scanner_sidebarToggle')
self.sidebarPanel = parentWindow.findChild(QWidget, 'scanner_sidebarPanel')
self.sidebarToggleButton = parentWindow.scanner_sidebarToggle
self.sidebarPanel = parentWindow.scanner_sidebarPanel
self.disconnectButton = parentWindow.findChild(QToolButton, 'scanner_disconnectButton')
self.settingsButton = parentWindow.findChild(QToolButton, 'scanner_settingsButton')
self.connectInfoButton = parentWindow.findChild(QToolButton, 'scanner_connectInfoButton')
self.disconnectButton = parentWindow.scanner_disconnectButton
self.settingsButton = parentWindow.scanner_settingsButton
self.connectInfoButton = parentWindow.scanner_connectInfoButton
self.volumeControlPanel = parentWindow.findChild(QWidget, 'scanner_volumeControl')
self.volumeSlider = parentWindow.findChild(QWidget, 'scanner_volumeSlider')
self.muteButton = parentWindow.findChild(QWidget, 'scanner_volumeMute')
self.volumeControlPanel = parentWindow.scanner_volumeControl
self.volumeSlider = parentWindow.scanner_volumeSlider
self.muteButton = parentWindow.scanner_volumeMute
self.entryEditButton = parentWindow.findChild(QToolButton, 'scanner_entryEditButton')
self.entryEditButton = parentWindow.scanner_entryEditButton
self.fnButton1.clicked.connect(self.onFnButton1)
self.fnButton2.clicked.connect(self.onFnButton2)
@ -81,7 +79,7 @@ class Scanner:
self.entryEditButton.setVisible(False)
self.delayLabel.setVisible(False)
self.scanModeLabel.setVisible(False)
parentWindow.findChild(QWidget, 'line_4').setVisible(False)
parentWindow.line_4.setVisible(False)
movie = QMovie("resources/bar-scan.gif")
movie.start()

2018
client/py/ui_scan_client.py Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.