diff --git a/QtTSAfilebrowse.py b/QtTSAfilebrowse.py
new file mode 100644
index 0000000..101e0ee
--- /dev/null
+++ b/QtTSAfilebrowse.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'filebrowse.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Filebrowse(object):
+ def setupUi(self, Filebrowse):
+ Filebrowse.setObjectName("Filebrowse")
+ Filebrowse.resize(818, 405)
+ self.listWidget = QtWidgets.QListWidget(Filebrowse)
+ self.listWidget.setGeometry(QtCore.QRect(10, 20, 301, 311))
+ self.listWidget.setObjectName("listWidget")
+ self.download = QtWidgets.QPushButton(Filebrowse)
+ self.download.setGeometry(QtCore.QRect(10, 350, 80, 26))
+ self.download.setObjectName("download")
+ self.picture = QtWidgets.QLabel(Filebrowse)
+ self.picture.setGeometry(QtCore.QRect(320, 20, 481, 321))
+ self.picture.setText("")
+ self.picture.setScaledContents(False)
+ self.picture.setObjectName("picture")
+ self.downloadBar = QtWidgets.QProgressBar(Filebrowse)
+ self.downloadBar.setGeometry(QtCore.QRect(100, 350, 211, 26))
+ self.downloadBar.setProperty("value", 0)
+ self.downloadBar.setObjectName("downloadBar")
+ self.downloadInfo = QtWidgets.QLabel(Filebrowse)
+ self.downloadInfo.setGeometry(QtCore.QRect(10, 380, 791, 20))
+ self.downloadInfo.setText("")
+ self.downloadInfo.setObjectName("downloadInfo")
+
+ self.retranslateUi(Filebrowse)
+ QtCore.QMetaObject.connectSlotsByName(Filebrowse)
+
+ def retranslateUi(self, Filebrowse):
+ _translate = QtCore.QCoreApplication.translate
+ Filebrowse.setWindowTitle(_translate("Filebrowse", "File List"))
+ self.download.setText(_translate("Filebrowse", "Save"))
diff --git a/QtTSApreferences.py b/QtTSApreferences.py
index 02dc0e1..b490d59 100644
--- a/QtTSApreferences.py
+++ b/QtTSApreferences.py
@@ -14,7 +14,7 @@
class Ui_Preferences(object):
def setupUi(self, Preferences):
Preferences.setObjectName("Preferences")
- Preferences.resize(800, 600)
+ Preferences.resize(817, 600)
self.layoutWidget = QtWidgets.QWidget(Preferences)
self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 411, 572))
self.layoutWidget.setObjectName("layoutWidget")
@@ -94,73 +94,51 @@ def setupUi(self, Preferences):
self.importButton.setObjectName("importButton")
self.gridLayout.addWidget(self.importButton, 4, 0, 1, 1)
self.layoutWidget1 = QtWidgets.QWidget(Preferences)
- self.layoutWidget1.setGeometry(QtCore.QRect(440, 10, 356, 571))
+ self.layoutWidget1.setGeometry(QtCore.QRect(440, 10, 361, 571))
self.layoutWidget1.setObjectName("layoutWidget1")
self.gridLayout_2 = QtWidgets.QGridLayout(self.layoutWidget1)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setObjectName("gridLayout_2")
- self.zeroLine = QtWidgets.QCheckBox(self.layoutWidget1)
- self.zeroLine.setChecked(False)
- self.zeroLine.setObjectName("zeroLine")
- self.gridLayout_2.addWidget(self.zeroLine, 2, 1, 1, 1)
- self.label = QtWidgets.QLabel(self.layoutWidget1)
- self.label.setObjectName("label")
- self.gridLayout_2.addWidget(self.label, 7, 0, 1, 1)
- self.minPoints = QtWidgets.QSpinBox(self.layoutWidget1)
- self.minPoints.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
- self.minPoints.setMinimum(25)
- self.minPoints.setMaximum(450)
- self.minPoints.setProperty("value", 450)
- self.minPoints.setObjectName("minPoints")
- self.gridLayout_2.addWidget(self.minPoints, 8, 1, 1, 1)
- self.label_14 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_13 = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
- self.label_14.setFont(font)
- self.label_14.setObjectName("label_14")
- self.gridLayout_2.addWidget(self.label_14, 10, 0, 1, 2)
- self.peakThreshold = QtWidgets.QSpinBox(self.layoutWidget1)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.peakThreshold.sizePolicy().hasHeightForWidth())
- self.peakThreshold.setSizePolicy(sizePolicy)
- self.peakThreshold.setMaximumSize(QtCore.QSize(83, 16777215))
- font = QtGui.QFont()
- font.setPointSize(9)
- self.peakThreshold.setFont(font)
- self.peakThreshold.setPrefix("")
- self.peakThreshold.setMinimum(-120)
- self.peakThreshold.setMaximum(-20)
- self.peakThreshold.setProperty("value", -90)
- self.peakThreshold.setObjectName("peakThreshold")
- self.gridLayout_2.addWidget(self.peakThreshold, 5, 1, 1, 1)
- spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_2.addItem(spacerItem, 16, 0, 1, 1)
- self.freqLO = QtWidgets.QDoubleSpinBox(self.layoutWidget1)
- self.freqLO.setDecimals(6)
- self.freqLO.setMinimum(0.0)
- self.freqLO.setMaximum(100000.0)
- self.freqLO.setProperty("value", 0.0)
- self.freqLO.setObjectName("freqLO")
- self.gridLayout_2.addWidget(self.freqLO, 12, 1, 1, 1)
+ self.label_13.setFont(font)
+ self.label_13.setObjectName("label_13")
+ self.gridLayout_2.addWidget(self.label_13, 11, 0, 1, 1)
self.rbw_x = QtWidgets.QSpinBox(self.layoutWidget1)
self.rbw_x.setMinimum(2)
self.rbw_x.setMaximum(10)
self.rbw_x.setProperty("value", 3)
self.rbw_x.setObjectName("rbw_x")
- self.gridLayout_2.addWidget(self.rbw_x, 7, 1, 1, 1)
- self.label_4 = QtWidgets.QLabel(self.layoutWidget1)
- self.label_4.setObjectName("label_4")
- self.gridLayout_2.addWidget(self.label_4, 9, 0, 1, 1)
- self.label_8 = QtWidgets.QLabel(self.layoutWidget1)
+ self.gridLayout_2.addWidget(self.rbw_x, 5, 1, 1, 1)
+ self.syncTime = QtWidgets.QCheckBox(self.layoutWidget1)
+ self.syncTime.setObjectName("syncTime")
+ self.gridLayout_2.addWidget(self.syncTime, 13, 1, 1, 1)
+ self.plus6Line = QtWidgets.QCheckBox(self.layoutWidget1)
+ self.plus6Line.setChecked(False)
+ self.plus6Line.setObjectName("plus6Line")
+ self.gridLayout_2.addWidget(self.plus6Line, 1, 1, 1, 1)
+ self.label = QtWidgets.QLabel(self.layoutWidget1)
+ self.label.setObjectName("label")
+ self.gridLayout_2.addWidget(self.label, 5, 0, 1, 1)
+ self.label_14 = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
- self.label_8.setFont(font)
- self.label_8.setObjectName("label_8")
- self.gridLayout_2.addWidget(self.label_8, 6, 0, 1, 1)
+ self.label_14.setFont(font)
+ self.label_14.setObjectName("label_14")
+ self.gridLayout_2.addWidget(self.label_14, 8, 0, 1, 2)
+ self.label_11 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_11.setObjectName("label_11")
+ self.gridLayout_2.addWidget(self.label_11, 1, 0, 1, 1)
+ self.maxPoints = QtWidgets.QSpinBox(self.layoutWidget1)
+ self.maxPoints.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
+ self.maxPoints.setMinimum(25)
+ self.maxPoints.setMaximum(100000)
+ self.maxPoints.setProperty("value", 30000)
+ self.maxPoints.setObjectName("maxPoints")
+ self.gridLayout_2.addWidget(self.maxPoints, 7, 1, 1, 1)
self.label_6 = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
@@ -168,56 +146,80 @@ def setupUi(self, Preferences):
self.label_6.setFont(font)
self.label_6.setObjectName("label_6")
self.gridLayout_2.addWidget(self.label_6, 0, 0, 1, 2)
+ self.label_10 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_10.setObjectName("label_10")
+ self.gridLayout_2.addWidget(self.label_10, 2, 0, 1, 1)
self.neg25Line = QtWidgets.QCheckBox(self.layoutWidget1)
self.neg25Line.setChecked(False)
self.neg25Line.setObjectName("neg25Line")
self.gridLayout_2.addWidget(self.neg25Line, 3, 1, 1, 1)
- self.label_11 = QtWidgets.QLabel(self.layoutWidget1)
- self.label_11.setObjectName("label_11")
- self.gridLayout_2.addWidget(self.label_11, 1, 0, 1, 1)
+ self.label_2 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_2.setObjectName("label_2")
+ self.gridLayout_2.addWidget(self.label_2, 12, 0, 1, 1)
+ self.label_4 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_4.setObjectName("label_4")
+ self.gridLayout_2.addWidget(self.label_4, 7, 0, 1, 1)
+ self.highLO = QtWidgets.QCheckBox(self.layoutWidget1)
+ self.highLO.setObjectName("highLO")
+ self.gridLayout_2.addWidget(self.highLO, 9, 1, 1, 1)
self.label_9 = QtWidgets.QLabel(self.layoutWidget1)
self.label_9.setObjectName("label_9")
self.gridLayout_2.addWidget(self.label_9, 3, 0, 1, 1)
self.label_15 = QtWidgets.QLabel(self.layoutWidget1)
self.label_15.setObjectName("label_15")
- self.gridLayout_2.addWidget(self.label_15, 11, 0, 1, 1)
- self.plus6Line = QtWidgets.QCheckBox(self.layoutWidget1)
- self.plus6Line.setChecked(False)
- self.plus6Line.setObjectName("plus6Line")
- self.gridLayout_2.addWidget(self.plus6Line, 1, 1, 1, 1)
- self.label_13 = QtWidgets.QLabel(self.layoutWidget1)
- self.label_13.setText("")
- self.label_13.setObjectName("label_13")
- self.gridLayout_2.addWidget(self.label_13, 13, 0, 1, 1)
- self.label_2 = QtWidgets.QLabel(self.layoutWidget1)
- self.label_2.setObjectName("label_2")
- self.gridLayout_2.addWidget(self.label_2, 5, 0, 1, 1)
- self.label_10 = QtWidgets.QLabel(self.layoutWidget1)
- self.label_10.setObjectName("label_10")
- self.gridLayout_2.addWidget(self.label_10, 2, 0, 1, 1)
- self.maxPoints = QtWidgets.QSpinBox(self.layoutWidget1)
- self.maxPoints.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
- self.maxPoints.setMinimum(25)
- self.maxPoints.setMaximum(100000)
- self.maxPoints.setProperty("value", 30000)
- self.maxPoints.setObjectName("maxPoints")
- self.gridLayout_2.addWidget(self.maxPoints, 9, 1, 1, 1)
- self.label_7 = QtWidgets.QLabel(self.layoutWidget1)
- font = QtGui.QFont()
- font.setBold(True)
- font.setWeight(75)
- self.label_7.setFont(font)
- self.label_7.setObjectName("label_7")
- self.gridLayout_2.addWidget(self.label_7, 4, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_15, 9, 0, 1, 1)
+ self.zeroLine = QtWidgets.QCheckBox(self.layoutWidget1)
+ self.zeroLine.setChecked(False)
+ self.zeroLine.setObjectName("zeroLine")
+ self.gridLayout_2.addWidget(self.zeroLine, 2, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(self.layoutWidget1)
self.label_3.setObjectName("label_3")
- self.gridLayout_2.addWidget(self.label_3, 8, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_3, 6, 0, 1, 1)
self.label_16 = QtWidgets.QLabel(self.layoutWidget1)
self.label_16.setObjectName("label_16")
- self.gridLayout_2.addWidget(self.label_16, 12, 0, 1, 1)
- self.highLO = QtWidgets.QCheckBox(self.layoutWidget1)
- self.highLO.setObjectName("highLO")
- self.gridLayout_2.addWidget(self.highLO, 11, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.label_16, 10, 0, 1, 1)
+ self.peakThreshold = QtWidgets.QSpinBox(self.layoutWidget1)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.peakThreshold.sizePolicy().hasHeightForWidth())
+ self.peakThreshold.setSizePolicy(sizePolicy)
+ self.peakThreshold.setMaximumSize(QtCore.QSize(83, 16777215))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ self.peakThreshold.setFont(font)
+ self.peakThreshold.setPrefix("")
+ self.peakThreshold.setMinimum(-120)
+ self.peakThreshold.setMaximum(-20)
+ self.peakThreshold.setProperty("value", -90)
+ self.peakThreshold.setObjectName("peakThreshold")
+ self.gridLayout_2.addWidget(self.peakThreshold, 12, 1, 1, 1)
+ self.label_8 = QtWidgets.QLabel(self.layoutWidget1)
+ font = QtGui.QFont()
+ font.setBold(True)
+ font.setWeight(75)
+ self.label_8.setFont(font)
+ self.label_8.setObjectName("label_8")
+ self.gridLayout_2.addWidget(self.label_8, 4, 0, 1, 1)
+ self.minPoints = QtWidgets.QSpinBox(self.layoutWidget1)
+ self.minPoints.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
+ self.minPoints.setMinimum(25)
+ self.minPoints.setMaximum(450)
+ self.minPoints.setProperty("value", 450)
+ self.minPoints.setObjectName("minPoints")
+ self.gridLayout_2.addWidget(self.minPoints, 6, 1, 1, 1)
+ self.freqLO = QtWidgets.QDoubleSpinBox(self.layoutWidget1)
+ self.freqLO.setDecimals(6)
+ self.freqLO.setMinimum(0.0)
+ self.freqLO.setMaximum(100000.0)
+ self.freqLO.setProperty("value", 0.0)
+ self.freqLO.setObjectName("freqLO")
+ self.gridLayout_2.addWidget(self.freqLO, 10, 1, 1, 1)
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout_2.addItem(spacerItem, 14, 0, 1, 1)
+ self.label_17 = QtWidgets.QLabel(self.layoutWidget1)
+ self.label_17.setObjectName("label_17")
+ self.gridLayout_2.addWidget(self.label_17, 13, 0, 1, 1)
self.retranslateUi(Preferences)
QtCore.QMetaObject.connectSlotsByName(Preferences)
@@ -232,22 +234,24 @@ def retranslateUi(self, Preferences):
self.label_12.setText(_translate("Preferences", "Filter on:"))
self.exportButton.setText(_translate("Preferences", "Export"))
self.importButton.setText(_translate("Preferences", "Import"))
- self.zeroLine.setText(_translate("Preferences", " 0dBm"))
+ self.label_13.setText(_translate("Preferences", "Miscellaneous"))
+ self.syncTime.setText(_translate("Preferences", "Sync to PC"))
+ self.plus6Line.setText(_translate("Preferences", "+6dBm"))
self.label.setText(_translate("Preferences", "Points / Resolution Bandwidth"))
self.label_14.setText(_translate("Preferences", "External Mixer / LNB"))
- self.peakThreshold.setSuffix(_translate("Preferences", "dBm"))
- self.freqLO.setSuffix(_translate("Preferences", "MHz"))
- self.label_4.setText(_translate("Preferences", "Auto maximum points"))
- self.label_8.setText(_translate("Preferences", "Scan Points Settings"))
+ self.label_11.setText(_translate("Preferences", "Absolute maximum"))
self.label_6.setText(_translate("Preferences", "Signal Level Reminder lines"))
+ self.label_10.setText(_translate("Preferences", "Max with auto attenuator"))
self.neg25Line.setText(_translate("Preferences", "-25dBm"))
- self.label_11.setText(_translate("Preferences", "Absolute maximum"))
+ self.label_2.setText(_translate("Preferences", "Peak marker detection threshold"))
+ self.label_4.setText(_translate("Preferences", "Auto maximum points"))
+ self.highLO.setText(_translate("Preferences", "True"))
self.label_9.setText(_translate("Preferences", "Max for best accuracy"))
self.label_15.setText(_translate("Preferences", "LO above displayed Freq"))
- self.plus6Line.setText(_translate("Preferences", "+6dBm"))
- self.label_2.setText(_translate("Preferences", "Detection Threshold"))
- self.label_10.setText(_translate("Preferences", "Max with auto attenuator"))
- self.label_7.setText(_translate("Preferences", "Peak Marker Settings"))
+ self.zeroLine.setText(_translate("Preferences", " 0dBm"))
self.label_3.setText(_translate("Preferences", "Auto minimum points"))
self.label_16.setText(_translate("Preferences", "LO Frequency"))
- self.highLO.setText(_translate("Preferences", "True"))
+ self.peakThreshold.setSuffix(_translate("Preferences", "dBm"))
+ self.label_8.setText(_translate("Preferences", "Scan Points Settings"))
+ self.freqLO.setSuffix(_translate("Preferences", "MHz"))
+ self.label_17.setText(_translate("Preferences", "Date and Time"))
diff --git a/QtTSAprefs.db b/QtTSAprefs.db
index 3e02207..fda8be8 100644
Binary files a/QtTSAprefs.db and b/QtTSAprefs.db differ
diff --git a/QtTinySA.py b/QtTinySA.py
index ff50d3c..0f8aed2 100755
--- a/QtTinySA.py
+++ b/QtTinySA.py
@@ -25,14 +25,18 @@
import csv
from platform import system
from PyQt5 import QtWidgets, QtCore
-from PyQt5.QtWidgets import QMessageBox, QDataWidgetMapper, QFileDialog
+from PyQt5.QtWidgets import QMessageBox, QDataWidgetMapper, QFileDialog, QInputDialog, QLineEdit
from PyQt5.QtSql import QSqlDatabase, QSqlRelation, QSqlRelationalTableModel, QSqlRelationalDelegate
+from PyQt5.QtGui import QPixmap
+from datetime import datetime
import pyqtgraph
import QtTinySpectrum # the GUI
import QtTSApreferences # the GUI preferences window
+import QtTSAfilebrowse
import struct
import serial
from serial.tools import list_ports
+from io import BytesIO
# For 3D
import pyqtgraph.opengl as pyqtgl
@@ -65,6 +69,7 @@ class analyser:
def __init__(self):
self.usb = None
self.sweeping = False
+ self.threadRunning = False
self.signals = WorkerSignals()
self.signals.result.connect(self.sigProcess)
self.signals.fullSweep.connect(self.updateGUI)
@@ -72,7 +77,6 @@ def __init__(self):
self.runTimer = QtCore.QElapsedTimer() # debug
self.scale = 174
self.scanMemory = 50
- # self.scan3D = False
self.surface = None
self.vGrid = None
self.usbCheck = QtCore.QTimer()
@@ -82,6 +86,8 @@ def __init__(self):
self.fifoTimer.timeout.connect(self.usbSend)
self.tinySA4 = None
self.maxF = 6000
+ self.directory = None
+ self.memF = BytesIO()
def openPort(self):
self.dev = None
@@ -102,7 +108,8 @@ def openPort(self):
self.usb = serial.Serial(self.dev, baudrate=576000)
logging.info(f'Serial port open: {self.usb.isOpen()}')
except serial.SerialException:
- logging.info('serial port exception')
+ logging.info('Serial port exception. Is your username in the "dialout" group?')
+ logging.info(f'groups: {os.getgroups()}')
popUp('Serial Port Exception', QMessageBox.Ok, QMessageBox.Critical)
if self.dev and self.usb:
self.initialise()
@@ -121,11 +128,11 @@ def isConnected(self):
self.usbCheck.stop()
def initialise(self):
- i = 0
+ i = 1
hardware = ''
- while hardware[:6] != 'tinySA' and i < 3: # try 3 times to detect TinySA
+ while hardware[:6] != 'tinySA' and i < 4: # try 3 times to detect TinySA
hardware = self.version()
- logging.info(f'{hardware[:16]}')
+ logging.info(f'Hardware detection attempt {i}: TinySA version: {hardware[:16]}')
i += 1
time.sleep(0.5)
# hardware = 'tinySA' # used for testing
@@ -153,6 +160,8 @@ def initialise(self):
ui.battery.setText(self.battery())
ui.version.setText(hardware[8:16])
+ self.setTime()
+
# connect the rbw & frequency boxes here or it causes startup index errors when they are populated
ui.rbw_box.currentIndexChanged.connect(rbwChanged)
ui.rbw_auto.clicked.connect(rbwChanged)
@@ -160,6 +169,7 @@ def initialise(self):
ui.stop_freq.editingFinished.connect(self.freq_changed)
ui.centre_freq.valueChanged.connect(lambda: self.freq_changed(True)) # centre/span mode
ui.span_freq.valueChanged.connect(lambda: self.freq_changed(True)) # centre/span mode
+ ui.band_box.currentIndexChanged.connect(band_changed)
ui.band_box.activated.connect(band_changed)
self.fifoTimer.start(500) # calls self.usbSend() every 500mS to execute serial commands whilst not scanning
@@ -205,7 +215,9 @@ def scan(self): # called by 'run' button
self.scanCount = 1
self.clearBuffer()
self.setRBW()
+ self.sampleRep()
self.runButton('Stop')
+ self.pause()
self.usbSend()
self.startMeasurement() # runs measurement in separate thread
except serial.SerialException:
@@ -235,15 +247,15 @@ def usbSend(self):
while self.fifo.qsize() > 0:
command = self.fifo.get(block=True, timeout=None)
logging.debug(command)
- self.usb.write(command)
+ self.usb.write(command.encode())
self.usb.read_until(b'ch> ') # skip command echo and prompt
def serialQuery(self, command):
self.usb.timeout = 1
logging.debug(command)
- self.usb.write(command)
- self.usb.read_until(command + b'\n') # skip command echo
- response = self.usb.read_until(b'ch> ')
+ self.usb.write(command.encode())
+ self.usb.read_until(command.encode() + b'\n') # skip command echo
+ response = self.usb.read_until(b'ch> ') # until prompt
logging.debug(response)
return response[:-6].decode() # remove prompt
@@ -253,6 +265,7 @@ def set_frequencies(self): # creates a numpy array of equi-spaced freqs in Hz.
points = self.setPoints()
frequencies = np.linspace(startF, stopF, points, dtype=np.int64)
logging.debug(f'frequencies = {frequencies}')
+ self.fPrecision(frequencies)
return frequencies
def freq_changed(self, centre=False):
@@ -270,7 +283,7 @@ def freq_changed(self, centre=False):
ui.centre_freq.setValue(startF + (stopF - startF) / 2)
ui.span_freq.setValue(stopF - startF)
ui.graphWidget.setXRange(startF, stopF)
- self.resume()
+ self.resume() # # without this command, the trace doesn't update
def freqOffset(self, frequencies): # for mixers or LNBs external to TinySA
startF = frequencies[0]
@@ -290,7 +303,7 @@ def freqOffset(self, frequencies): # for mixers or LNBs external to TinySA
def setRBW(self): # may be called by measurement thread as well as normally
rbw = ui.rbw_box.currentText() # ui values are discrete ones in kHz
logging.debug(f'rbw = {rbw}')
- command = f'rbw {rbw}\r'.encode()
+ command = f'rbw {rbw}\r'
self.fifo.put(command)
def setPoints(self): # may be called by measurement thread as well as normally
@@ -339,19 +352,19 @@ def measurement(self, frequencies, readings): # runs in a separate thread
self.usb.timeout = self.sweepTimeout(frequencies)
if preferences.freqLO != 0:
startF, stopF = self.freqOffset(frequencies)
- command = f'scanraw {int(startF)} {int(stopF)} {int(points)}\r'.encode()
+ command = f'scanraw {int(startF)} {int(stopF)} {int(points)}\r'
else:
- command = f'scanraw {int(frequencies[0])} {int(frequencies[-1])} {int(points)}\r'.encode()
+ command = f'scanraw {int(frequencies[0])} {int(frequencies[-1])} {int(points)}\r'
logging.debug(f'measurement: command = {command}')
- self.usb.write(command)
+ self.usb.write(command.encode())
index = 0
# self.runTimer.start() # debug
- self.usb.read_until(command + b'\n{') # skip command echo
+ self.usb.read_until(command.encode() + b'\n{') # skip command echo
dataBlock = ''
while dataBlock != b'}ch' and index < points: # if '}ch' it's reached the end of the scan points
dataBlock = (self.usb.read(3)) # read a block of 3 bytes of data
logging.debug(f'dataBlock: {dataBlock}\n')
- if dataBlock == b'}ch':
+ if dataBlock == b'}ch' or dataBlock == b'}': # from FW165 jog button press returns different value
logging.info('jog button pressed')
self.sweeping = False
break
@@ -527,26 +540,26 @@ def runButton(self, action):
def pause(self):
# pauses the sweeping in either input or output mode
- command = 'pause\r'.encode()
+ command = 'pause\r'
self.fifo.put(command)
def resume(self):
# resumes the sweeping in either input or output mode
- command = 'resume\r'.encode()
+ command = 'resume\r'
self.fifo.put(command)
def reset(self):
# not yet found any detail for what is actually reset
- command = 'reset\r'.encode()
+ command = 'reset\r'
self.fifo.put(command)
def battery(self):
- command = 'vbat\r'.encode()
+ command = 'vbat\r'
vbat = self.serialQuery(command)
return vbat
def version(self):
- command = 'version\r'.encode()
+ command = 'version\r'
version = self.serialQuery(command)
return version
@@ -554,23 +567,107 @@ def spur(self):
sType = ui.spur_box.checkState()
options = {0: 'Spur Off', 1: 'Spur Auto', 2: 'Spur On'}
ui.spur_box.setText(options.get(sType))
- options = {0: 'spur off\r'.encode(), 1: 'spur auto\r'.encode(), 2: 'spur on\r'.encode()}
+ options = {0: 'spur off\r', 1: 'spur auto\r', 2: 'spur on\r'}
command = options.get(sType)
self.fifo.put(command)
def lna(self):
if ui.lna_box.isChecked():
- command = 'lna on\r'.encode()
+ command = 'lna on\r'
ui.atten_auto.setEnabled(False) # attenuator and lna are switched so mutually exclusive
ui.atten_auto.setChecked(False)
ui.atten_box.setEnabled(False)
ui.atten_box.setValue(0)
else:
- command = 'lna off\r'.encode()
+ command = 'lna off\r'
ui.atten_auto.setEnabled(True)
ui.atten_auto.setChecked(True)
self.fifo.put(command)
+ def setTime(self):
+ if self.tinySA4 and preferences.syncTime.isChecked():
+ dt = datetime.now()
+ y = dt.year - 2000
+ command = f'time b 0x{y}{dt.month:02d}{dt.day:02d} 0x{dt.hour:02d}{dt.minute:02d}{dt.second:02d}\r'
+ self.fifo.put(command)
+
+ def example(self):
+ command = 'example\r'
+ self.fifo.put(command)
+
+ def sampleRep(self):
+ # sets the number of repeat measurements at each frequency point to the value in the GUI
+ command = f'repeat {ui.sampleRepeat.value()}\r'
+ self.fifo.put(command)
+
+ def fPrecision(self, frequencies): # sets the marker indicated frequency precision
+ fInc = frequencies[1] - frequencies[0]
+ if fInc > 0:
+ self.dp = np.clip(int(np.log10(frequencies[0] / fInc)), 0, 5) # number of decicimal places required
+ logging.debug(f'fPrecision: fInc = {fInc} dp = {self.dp}')
+ else:
+ self.dp = 6
+
+ def listSD(self):
+ if self.usb:
+ self.clearBuffer() # clear the USB serial buffer
+ command = 'sd_list\r'
+ ls = self.serialQuery(command)
+ return ls
+
+ def readSD(self, fileName):
+ command = ('sd_read %s\r' % fileName)
+ self.usb.write(command.encode())
+ self.usb.readline() # discard empty line
+ format_string = "<1i" # little-endian single integer of 4 bytes
+ self.usb.timeout = None
+ buffer = self.usb.read(4)
+ size = struct.unpack(format_string, buffer)
+ size = size[0]
+ data = self.usb.read(size)
+ self.usb.timeout = 1
+ return data
+
+ def dialogBrowse(self):
+ if self.threadRunning:
+ popUp("Cannot browse tinySA whilst a scan is running", QMessageBox.Ok, QMessageBox.Information)
+ return
+ elif self.usb:
+ SD = self.listSD()
+ filebrowse.listWidget.clear()
+ ls = []
+ for i in range(len(SD.splitlines())):
+ ls.append(SD.splitlines()[i].split(" ")[0])
+ filebrowse.listWidget.insertItems(0, ls)
+ fwindow.show()
+ else:
+ popUp('TinySA not found', QMessageBox.Ok, QMessageBox.Critical)
+
+ def fileDownload(self):
+ selected = filebrowse.listWidget.currentItem().text() # the file selected in the list widget
+ if self.directory: # already saved a file so use the same folder path as the default
+ folder = os.path.join(self.directory, selected)
+ fileName = QFileDialog.getSaveFileName(caption="Save As", directory=folder)
+ else:
+ fileName = QFileDialog.getSaveFileName(caption="Save As", directory=selected)
+ with open(str(fileName[0]), "wb") as file:
+ file.write(self.memF.getvalue())
+ self.directory = os.path.dirname(fileName[0])
+ filebrowse.downloadInfo.setText(self.directory) # show the path where the file was saved
+
+ def fileShow(self):
+ filebrowse.downloadBar.setValue(0) # reset the fake progress bar
+ filebrowse.picture.clear()
+ fileName = filebrowse.listWidget.currentItem().text()
+ self.clearBuffer() # clear the tinySA serial buffer
+ filebrowse.downloadBar.setValue(20) # update the fake progress bar to show start of download
+ self.memF.write(self.readSD(fileName))
+ if fileName[-3:] == 'bmp':
+ pixmap = QPixmap()
+ pixmap.loadFromData(self.memF.getvalue())
+ filebrowse.picture.setPixmap(pixmap)
+ filebrowse.downloadBar.setValue(100) # update the fake progress bar to complete
+
class display:
def __init__(self, name, pen):
@@ -672,7 +769,7 @@ def updateMarker(self, frequencies, readings, fPeaks): # called by updateGUI()
markerF = options.get(self.markerType)
if markerF * 1e6 < np.min(frequencies) or markerF * 1e6 > np.max(frequencies):
# marker is out of scan range so just show its frequency
- self.vline.label.setText(f'M{self.vline.name()} {self.vline.value():.3f}MHz')
+ self.vline.label.setText(f'M{self.vline.name()} {self.vline.value():.{tinySA.dp}f}MHz')
else:
# marker is in scan range
fIndex = np.argmin(np.abs(frequencies - (markerF * 1e6))) # find closest value in freq array
@@ -680,14 +777,14 @@ def updateMarker(self, frequencies, readings, fPeaks): # called by updateGUI()
if dBm > S4.hline.value() or self.markerType[:4] != 'Peak':
self.vline.setValue(frequencies[fIndex] / 1e6) # set to the discrete value from frequencies[]
if self.markerType == 'Delta':
- self.vline.label.setText(f'M{self.vline.name()} {chr(916)}{self.deltaF:.3f}MHz {dBm:.1f}dBm')
+ self.vline.label.setText(f'M{self.vline.name()} {chr(916)}{self.deltaF:.{tinySA.dp}f}MHz {dBm:.1f}dBm')
else:
- self.vline.label.setText(f'M{self.vline.name()} {self.vline.value():.3f}MHz {dBm:.1f}dBm')
+ self.vline.label.setText(f'M{self.vline.name()} {self.vline.value():.{tinySA.dp}f}MHz {dBm:.1f}dBm')
def addFreqMarker(self, freq, colour, name, position): # adds simple freq marker without full marker capability
if ui.presetLabel.isChecked():
self.marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine),
- label=name, labelOpts={'position': position, 'color': (colour)})
+ label=name, labelOpts={'position': position, 'color': (colour)})
self.marker.label.setMovable(True)
else:
self.marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine))
@@ -728,40 +825,30 @@ class database():
def __init__(self):
self.db = None
self.dbName = "QtTSAprefs.db"
- self.personalDir = platformdirs.user_config_dir(appname=app.applicationName(), ensure_exists=True)
- self.globalDir = platformdirs.site_config_dir(appname=app.applicationName())
+ self.personalDir = platformdirs.user_config_dir(appname=app.applicationName(), appauthor=False)
+ self.globalDir = platformdirs.site_config_dir(appname=app.applicationName(), appauthor=False)
self.workingDirs = [os.path.dirname(__file__), os.path.dirname(os.path.realpath(__file__)), os.getcwd()]
self.dbpath = self._getPersonalisedPath()
def _getPersonalisedPath(self):
- returnpath = None
- # check if config database file exists in ~/.config/qttinysa/
- if os.path.exists(os.path.join(self.personalDir, self.dbName)):
- returnpath = self.personalDir
+ if os.path.exists(os.path.join(self.personalDir, self.dbName)): # check if personal config database file exists
logging.info(f'Personal configuration database found at {self.personalDir}')
- elif os.path.exists(os.path.join(self.globalDir, self.dbName)):
- logging.info(f'Personal configuration database not found in {self.personalDir}')
- c = shutil.copy(os.path.join(self.globalDir, self.dbName), self.personalDir)
- if os.path.exists(os.path.join(self.personalDir, self.dbName)):
- returnpath = self.personalDir
- logging.info(f'Global configuration database copied to {c}')
- popUp(f'Personal configuration database created at \n{c}', QMessageBox.Ok, QMessageBox.Information)
- if returnpath is None:
- # no config database file found in personal or global directories
- logging.info(f'No configuration database file exists in {self.personalDir} or {self.globalDir}')
- # Look for one in the current working folder and in the folder where the python file is stored (or linked to):
- # In case QtTinySA is called from outside the stored folder.
- for workingDir in self.workingDirs:
- if os.path.exists(os.path.join(workingDir, self.dbName)):
- logging.info(f'Copying configuration database from {workingDir}')
- c = shutil.copy(os.path.join(workingDir, self.dbName), self.personalDir)
- if os.path.exists(os.path.join(self.personalDir, self.dbName)):
- returnpath = self.personalDir
- logging.info(f'Personal configuration database created at {c}')
- popUp(f'Personal configuration database created at \n{c}', QMessageBox.Ok, QMessageBox.Information)
- else:
- raise FileNotFoundError("Unable to create a personal configuration database")
- return returnpath
+ return self.personalDir
+ if not os.path.exists(self.personalDir):
+ os.mkdir(self.personalDir)
+ if os.path.exists(os.path.join(self.globalDir, self.dbName)):
+ logging.info(f'Global configuration database found at {self.globalDir}')
+ shutil.copy(os.path.join(self.globalDir, self.dbName), self.personalDir)
+ logging.info(f'Global configuration database copied from {self.globalDir} to {self.personalDir}')
+ return self.personalDir
+ logging.info(f'No configuration database file exists in {self.personalDir} or {self.globalDir}')
+ # Look in current working folder & where the python file is stored/linked from
+ for workingDir in self.workingDirs:
+ if os.path.exists(os.path.join(workingDir, self.dbName)):
+ shutil.copy(os.path.join(workingDir, self.dbName), self.personalDir)
+ logging.info(f'Personal configuration database copied from {workingDir} to {self.personalDir}')
+ return self.personalDir
+ raise FileNotFoundError("Unable to find the configuration database QtTSAprefs.db")
def connect(self):
self.db = QSqlDatabase.addDatabase('QSQLITE')
@@ -788,6 +875,7 @@ def __init__(self, tableName):
self.tm = QSqlRelationalTableModel()
self.dwm = QDataWidgetMapper()
self.currentRow = 0
+ self.currentBand = 0
def createTableModel(self):
self.tm.setTable(self.tableName)
@@ -820,10 +908,12 @@ def tableClicked(self):
def insertData(self, **data):
record = self.tm.record()
+ logging.info(f'insertData: record = {record}')
for key, value in data.items():
+ logging.info(f'insertData: key = {key} value={value}')
record.setValue(str(key), value)
self.tm.insertRecord(-1, record)
- self.tm.select()
+ # self.tm.select()
self.tm.layoutChanged.emit()
self.dwm.submit()
@@ -832,13 +922,16 @@ def filterType(self, prefsDialog, boxText):
if prefsDialog:
if boxText == 'show all':
sql = ''
+ self.tm.setFilter(sql)
else:
sql = 'visible = "1" AND preset = "' + boxText + '"'
if boxText == 'show all':
sql = 'visible = "1"'
if tinySA.tinySA4 is False: # It's a tinySA basic with limited frequency range
sql = sql + ' AND startF <= "960"'
- bands.tm.setFilter(sql)
+ index = ui.band_box.currentIndex()
+ self.tm.setFilter(sql)
+ ui.band_box.setCurrentIndex(index)
def readCSV(self, fileName):
with open(fileName, "r") as fileInput:
@@ -849,7 +942,7 @@ def readCSV(self, fileName):
# don't understand how to make relation work for these fields
if key == 'preset':
value = presetID(value)
- if key.lower() == 'colour':
+ if key == 'colour':
value = colourID(value)
if key == 'value':
value = int(eval(value))
@@ -893,14 +986,14 @@ def mapWidget(self, modelName): # maps the widget combo-box fields to the datab
def band_changed():
index = ui.band_box.currentIndex()
- if bandstype.tm.record(ui.filterBox.currentIndex()).value('type') == 'band':
- startF = bands.tm.record(index).value('StartF')
- stopF = bands.tm.record(index).value('StopF')
+ if bandselect.tm.record(index).value('stopF') != '':
+ startF = bandselect.tm.record(index).value('StartF')
+ stopF = bandselect.tm.record(index).value('StopF')
ui.start_freq.setValue(startF)
ui.stop_freq.setValue(stopF)
tinySA.freq_changed(False) # start/stop mode
else:
- centreF = bands.tm.record(index).value('StartF')
+ centreF = bandselect.tm.record(index).value('StartF')
ui.centre_freq.setValue(centreF)
ui.span_freq.setValue(1)
tinySA.freq_changed(True) # centre mode
@@ -908,18 +1001,27 @@ def band_changed():
def addBandPressed():
- if ui.marker1.isChecked() and ui.marker2.isChecked():
+ if not ui.marker1.isChecked():
+ message = 'Please enable Marker 1'
+ popUp(message, QMessageBox.Ok, QMessageBox.Information)
+ return
+ if ui.marker1.isChecked() and ui.marker2.isChecked(): # Two markers are to set the band limits of a new band
if S1.vline.value() >= S2.vline.value():
message = 'M1 frequency >= M2 frequency'
popUp(message, QMessageBox.Ok, QMessageBox.Information)
return
- bandName = 'M' + str(round(S1.vline.value(), 6))
ID = presetID(str(ui.filterBox.currentText()))
- bands.insertData(name=bandName, preset=ID, startF=f'{S1.vline.value():.6f}',
- stopF=f'{S2.vline.value():.6f}', value=1, colour="aliceblue")
- else:
- message = 'M1 and M2 must both be enabled to add a new Band'
- popUp(message, QMessageBox.Ok, QMessageBox.Information)
+ title = "New Frequency Band"
+ message = "Enter a name for the new band."
+ bandName, ok = QInputDialog.getText(None, title, message, QLineEdit.Normal, "")
+ bands.insertData(name=bandName, type=ID, startF=f'{S1.vline.value():.6f}',
+ stopF=f'{S2.vline.value():.6f}', visible=1, colour=colourID('green')) # colourID(value)
+ else: # If only Marker 1 is enabled then this creates a spot Frequency marker
+ title = "New Spot Frequency Marker"
+ message = "Enter a name for the Spot Frequency"
+ spotName, ok = QInputDialog.getText(None, title, message, QLineEdit.Normal, "")
+ bands.insertData(name=spotName, type=12, startF=f'{S1.vline.value():.6f}',
+ stopF='', visible=1, colour=colourID('orange')) # preset 12 is Marker (spot frequency).
def attenuate_changed():
@@ -930,15 +1032,18 @@ def attenuate_changed():
else:
if not ui.lna_box.isChecked(): # attenuator and lna are switched so mutually exclusive
ui.atten_box.setEnabled(True)
- command = f'attenuate {str(atten)}\r'.encode()
+ command = f'attenuate {str(atten)}\r'
tinySA.fifo.put(command)
def rbwChanged():
if ui.rbw_auto.isChecked(): # can't calculate Points because we don't know what the RBW will be
ui.rbw_box.setEnabled(False)
+ ui.points_auto.setChecked(False)
+ ui.points_auto.setEnabled(False)
else:
ui.rbw_box.setEnabled(True)
+ ui.points_auto.setEnabled(True)
tinySA.setRBW() # if measurement thread is running, calling setRBW() will force it to update scan parameters
@@ -948,7 +1053,7 @@ def pointsChanged():
ui.rbw_box.setEnabled(True)
else:
ui.points_box.setEnabled(True)
- tinySA.resume()
+ tinySA.resume() # without this command, the trace doesn't update
def memChanged():
@@ -985,7 +1090,7 @@ def setPreferences():
checkboxes.dwm.submit()
bands.tm.submitAll()
S4.hline.setValue(preferences.peakThreshold.value())
- bands.filterType(False, ui.filterBox.currentText())
+ bandselect.filterType(False, ui.filterBox.currentText())
if ui.presetMarker.isChecked():
freqMarkers()
isMixerMode()
@@ -993,7 +1098,7 @@ def setPreferences():
def dialogPrefs():
bands.filterType(True, preferences.filterBox.currentText())
- bands.tm.select()
+ bands.tm.select() # stopping marker add
bands.currentRow = 0
preferences.freqBands.selectRow(bands.currentRow)
pwindow.show()
@@ -1004,6 +1109,7 @@ def about():
.format(app.applicationVersion(), config.dbpath))
popUp(message, QMessageBox.Ok, QMessageBox.Information)
+
##############################################################################
# other methods
@@ -1025,6 +1131,7 @@ def exit_handler():
while tinySA.threadRunning:
time.sleep(0.1) # wait for measurements to stop
tinySA.resume()
+ tinySA.usbSend()
tinySA.closePort() # close USB connection
config.disconnect() # close database
logging.info('QtTinySA Closed')
@@ -1040,7 +1147,7 @@ def popUp(message, button, icon):
def freqMarkers():
- presetmarker.tm.select()
+ # presetmarker.tm.select()
S1.delFreqMarkers()
S2.delFreqMarkers()
for i in range(0, presetmarker.tm.rowCount()):
@@ -1049,11 +1156,11 @@ def freqMarkers():
colour = presetmarker.tm.record(i).value('colour')
name = presetmarker.tm.record(i).value('name')
if ui.presetMarker.isChecked() and presetmarker.tm.record(i).value('visible')\
- and presetmarker.tm.record(i).value('type') != 'band':
+ and presetmarker.tm.record(i).value('stopF') == '':
S1.addFreqMarker(startF, colour, name, 0.05)
if ui.presetLabel.isChecked() and ui.presetLabel.checkState() == 2:
S1.marker.label.setAngle(90)
- if presetmarker.tm.record(i).value('type') == 'band':
+ if presetmarker.tm.record(i).value('stopF') != '':
stopF = presetmarker.tm.record(i).value('StopF')
S1.addFreqMarker(startF, colour, name, 0.98)
S2.addFreqMarker(stopF, colour, name, 0.98)
@@ -1123,7 +1230,7 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
app = QtWidgets.QApplication([]) # create QApplication for the GUI
app.setApplicationName('QtTinySA')
-app.setApplicationVersion(' v0.10.3')
+app.setApplicationVersion(' v0.10.6')
window = QtWidgets.QMainWindow()
ui = QtTinySpectrum.Ui_MainWindow()
ui.setupUi(window)
@@ -1132,6 +1239,10 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
preferences = QtTSApreferences.Ui_Preferences()
preferences.setupUi(pwindow)
+fwindow = QtWidgets.QDialog() # fwindow is the filebrowse dialogue box
+filebrowse = QtTSAfilebrowse.Ui_Filebrowse()
+filebrowse.setupUi(fwindow)
+
# Traces & markers
S1 = display('1', yellow)
S2 = display('2', magenta)
@@ -1141,7 +1252,6 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
# Data models for configuration settings
config = database()
config.connect()
-bands = modelView('frequencies')
checkboxes = modelView('checkboxes')
numbers = modelView('numbers')
markers = modelView('marker')
@@ -1152,16 +1262,18 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
bandstype = modelView('freqtype')
colours = modelView('SVGColour')
maps = modelView('mapping')
-
-presetmarker = modelView(('frequencies'))
+bands = modelView('frequencies')
+presetmarker = modelView('frequencies')
+bandselect = modelView('frequencies')
###############################################################################
# GUI settings
# pyqtgraph settings for spectrum display
ui.graphWidget.disableAutoRange() # supposed to make pyqtgraph plot faster
+#
ui.graphWidget.setYRange(-110, 5)
-ui.graphWidget.setXRange(87.5, 108)
+# ui.graphWidget.setXRange(87.5, 108)
ui.graphWidget.setBackground('k') # black
ui.graphWidget.showGrid(x=True, y=True)
@@ -1223,7 +1335,7 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
# frequency band markers
ui.presetMarker.clicked.connect(freqMarkers)
-ui.presetLabel.stateChanged.connect(freqMarkerLabel)
+ui.presetLabel.clicked.connect(freqMarkerLabel)
ui.mToBand.clicked.connect(addBandPressed)
ui.filterBox.currentTextChanged.connect(freqMarkers)
@@ -1239,6 +1351,8 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
ui.t3_type.activated.connect(S3.tType)
ui.t4_type.activated.connect(S4.tType)
+ui.sampleRepeat.valueChanged.connect(tinySA.sampleRep)
+
# 3D graph controls
ui.orbitL.clicked.connect(lambda: tinySA.orbit3D(1, True))
ui.orbitR.clicked.connect(lambda: tinySA.orbit3D(-1, True))
@@ -1266,22 +1380,33 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
preferences.deleteAll.clicked.connect(lambda: bands.deleteRow(False))
preferences.freqBands.clicked.connect(bands.tableClicked)
preferences.filterBox.currentTextChanged.connect(lambda: bands.filterType(True, preferences.filterBox.currentText()))
-ui.filterBox.currentTextChanged.connect(lambda: bands.filterType(False, ui.filterBox.currentText()))
+ui.filterBox.currentTextChanged.connect(lambda: bandselect.filterType(False, ui.filterBox.currentText()))
ui.actionPreferences.triggered.connect(dialogPrefs) # open preferences dialogue when its menu is clicked
ui.actionAbout_QtTinySA.triggered.connect(about)
pwindow.finished.connect(setPreferences) # update database checkboxes table on dialogue window close
preferences.exportButton.pressed.connect(exportData)
preferences.importButton.pressed.connect(importData)
+# filebrowse
+ui.actionBrowse_TinySA.triggered.connect(tinySA.dialogBrowse)
+filebrowse.download.clicked.connect(tinySA.fileDownload)
+filebrowse.listWidget.itemSelectionChanged.connect(tinySA.fileShow)
+
+# Quit
+ui.actionQuit.triggered.connect(app.closeAllWindows)
+
###############################################################################
# set up the application
logging.info(f'{app.applicationName()}{app.applicationVersion()}')
# table models - read/write views of the configuration data
+
+# field mapping of the checkboxes from the database
maps.createTableModel()
maps.tm.select()
+# to populate the preset bands and markers relational table in the preferences dialogue
bands.createTableModel()
bands.tm.setSort(3, QtCore.Qt.AscendingOrder)
bands.tm.setHeaderData(5, QtCore.Qt.Horizontal, 'visible')
@@ -1290,29 +1415,35 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour.
bands.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'preset')) # set 'type' column to a freq type choice combo box
bands.tm.setRelation(5, QSqlRelation('boolean', 'ID', 'value')) # set 'view' column to a True/False choice combo box
bands.tm.setRelation(6, QSqlRelation('SVGColour', 'ID', 'colour')) # set 'marker' column to a colours choice combo box
-
presets = QSqlRelationalDelegate(preferences.freqBands)
preferences.freqBands.setItemDelegate(presets)
colHeader = preferences.freqBands.horizontalHeader()
colHeader.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
+# for the filter combo box in the preferences dialogue
bandstype.createTableModel()
bandstype.tm.select()
+# to lookup the preset bands and markers colours because can't get the relationships to work
colours.createTableModel()
colours.tm.select()
+# for the preset markers, which need different filtering to the preferences dialogue
presetmarker.createTableModel()
presetmarker.tm.setRelation(6, QSqlRelation('SVGColour', 'ID', 'colour'))
-presetmarker.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'type'))
+presetmarker.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'preset'))
+presetmarker.tm.setSort(3, QtCore.Qt.AscendingOrder)
presetmarker.tm.select()
-# populate the band presets combo box
-ui.band_box.setModel(bands.tm)
+# populate the ui band selection combo box, which needs different filter to preferences dialogue and preset markers
+bandselect.createTableModel()
+bandselect.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'preset'))
+bandselect.tm.setSort(3, QtCore.Qt.AscendingOrder)
+ui.band_box.setModel(bandselect.tm)
ui.band_box.setModelColumn(1)
-bands.tm.select() # initially select the data in the model
+bandselect.tm.select()
-# populate the preferences and main GUI filter combo boxes
+# populate the preferences dialogue and ui filter combo boxes
preferences.filterBox.setModel(bandstype.tm)
preferences.filterBox.setModelColumn(1)
ui.filterBox.setModel(bandstype.tm)
diff --git a/QtTinySpectrum.py b/QtTinySpectrum.py
index 89220d3..c7e05b3 100644
--- a/QtTinySpectrum.py
+++ b/QtTinySpectrum.py
@@ -14,7 +14,7 @@
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
- MainWindow.resize(1000, 603)
+ MainWindow.resize(1024, 614)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -39,39 +39,14 @@ def setupUi(self, MainWindow):
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_3 = QtWidgets.QGridLayout()
self.gridLayout_3.setObjectName("gridLayout_3")
- spacerItem = QtWidgets.QSpacerItem(17, 13, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_3.addItem(spacerItem, 22, 0, 1, 1)
- self.atten_auto = QtWidgets.QCheckBox(self.ViewNormal)
+ self.trace4 = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
font.setBold(True)
font.setWeight(75)
- self.atten_auto.setFont(font)
- self.atten_auto.setChecked(True)
- self.atten_auto.setObjectName("atten_auto")
- self.gridLayout_3.addWidget(self.atten_auto, 3, 0, 1, 1)
- self.t2_type = QtWidgets.QComboBox(self.ViewNormal)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.t2_type.sizePolicy().hasHeightForWidth())
- self.t2_type.setSizePolicy(sizePolicy)
- font = QtGui.QFont()
- font.setPointSize(7)
- self.t2_type.setFont(font)
- self.t2_type.setObjectName("t2_type")
- self.gridLayout_3.addWidget(self.t2_type, 15, 0, 1, 1)
- self.version = QtWidgets.QLabel(self.ViewNormal)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.version.sizePolicy().hasHeightForWidth())
- self.version.setSizePolicy(sizePolicy)
- font = QtGui.QFont()
- font.setPointSize(7)
- self.version.setFont(font)
- self.version.setObjectName("version")
- self.gridLayout_3.addWidget(self.version, 24, 0, 1, 1)
+ self.trace4.setFont(font)
+ self.trace4.setObjectName("trace4")
+ self.gridLayout_3.addWidget(self.trace4, 20, 0, 1, 1)
self.spur_box = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
@@ -80,14 +55,17 @@ def setupUi(self, MainWindow):
self.spur_box.setTristate(True)
self.spur_box.setObjectName("spur_box")
self.gridLayout_3.addWidget(self.spur_box, 1, 0, 1, 1)
- self.trace4 = QtWidgets.QCheckBox(self.ViewNormal)
+ self.t2_type = QtWidgets.QComboBox(self.ViewNormal)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.t2_type.sizePolicy().hasHeightForWidth())
+ self.t2_type.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(7)
- font.setBold(True)
- font.setWeight(75)
- self.trace4.setFont(font)
- self.trace4.setObjectName("trace4")
- self.gridLayout_3.addWidget(self.trace4, 18, 0, 1, 1)
+ self.t2_type.setFont(font)
+ self.t2_type.setObjectName("t2_type")
+ self.gridLayout_3.addWidget(self.t2_type, 17, 0, 1, 1)
self.t4_type = QtWidgets.QComboBox(self.ViewNormal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -98,7 +76,18 @@ def setupUi(self, MainWindow):
font.setPointSize(7)
self.t4_type.setFont(font)
self.t4_type.setObjectName("t4_type")
- self.gridLayout_3.addWidget(self.t4_type, 19, 0, 1, 1)
+ self.gridLayout_3.addWidget(self.t4_type, 21, 0, 1, 1)
+ self.t3_type = QtWidgets.QComboBox(self.ViewNormal)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.t3_type.sizePolicy().hasHeightForWidth())
+ self.t3_type.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ self.t3_type.setFont(font)
+ self.t3_type.setObjectName("t3_type")
+ self.gridLayout_3.addWidget(self.t3_type, 19, 0, 1, 1)
self.atten_box = QtWidgets.QSpinBox(self.ViewNormal)
self.atten_box.setEnabled(False)
font = QtGui.QFont()
@@ -110,6 +99,51 @@ def setupUi(self, MainWindow):
self.atten_box.setProperty("value", 0)
self.atten_box.setObjectName("atten_box")
self.gridLayout_3.addWidget(self.atten_box, 4, 0, 1, 1)
+ self.version = QtWidgets.QLabel(self.ViewNormal)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.version.sizePolicy().hasHeightForWidth())
+ self.version.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ self.version.setFont(font)
+ self.version.setObjectName("version")
+ self.gridLayout_3.addWidget(self.version, 26, 0, 1, 1)
+ self.t1_type = QtWidgets.QComboBox(self.ViewNormal)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.t1_type.sizePolicy().hasHeightForWidth())
+ self.t1_type.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ self.t1_type.setFont(font)
+ self.t1_type.setModelColumn(0)
+ self.t1_type.setObjectName("t1_type")
+ self.gridLayout_3.addWidget(self.t1_type, 14, 0, 1, 1)
+ self.points_box = QtWidgets.QSpinBox(self.ViewNormal)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ self.points_box.setFont(font)
+ self.points_box.setSuffix("")
+ self.points_box.setMinimum(1)
+ self.points_box.setMaximum(30000)
+ self.points_box.setSingleStep(100)
+ self.points_box.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
+ self.points_box.setProperty("value", 400)
+ self.points_box.setObjectName("points_box")
+ self.gridLayout_3.addWidget(self.points_box, 11, 0, 1, 1)
+ self.points_auto = QtWidgets.QCheckBox(self.ViewNormal)
+ self.points_auto.setEnabled(True)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ font.setBold(True)
+ font.setWeight(75)
+ self.points_auto.setFont(font)
+ self.points_auto.setChecked(True)
+ self.points_auto.setObjectName("points_auto")
+ self.gridLayout_3.addWidget(self.points_auto, 10, 0, 1, 1)
self.mixerMode = QtWidgets.QLabel(self.ViewNormal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -128,15 +162,33 @@ def setupUi(self, MainWindow):
self.mixerMode.setScaledContents(False)
self.mixerMode.setAlignment(QtCore.Qt.AlignCenter)
self.mixerMode.setObjectName("mixerMode")
- self.gridLayout_3.addWidget(self.mixerMode, 23, 0, 1, 1)
- self.lna_box = QtWidgets.QCheckBox(self.ViewNormal)
+ self.gridLayout_3.addWidget(self.mixerMode, 25, 0, 1, 1)
+ self.atten_auto = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
- font.setBold(False)
- font.setWeight(50)
- self.lna_box.setFont(font)
- self.lna_box.setObjectName("lna_box")
- self.gridLayout_3.addWidget(self.lna_box, 0, 0, 1, 1)
+ font.setBold(True)
+ font.setWeight(75)
+ self.atten_auto.setFont(font)
+ self.atten_auto.setChecked(True)
+ self.atten_auto.setObjectName("atten_auto")
+ self.gridLayout_3.addWidget(self.atten_auto, 3, 0, 1, 1)
+ self.trace3 = QtWidgets.QCheckBox(self.ViewNormal)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ font.setBold(True)
+ font.setWeight(75)
+ self.trace3.setFont(font)
+ self.trace3.setObjectName("trace3")
+ self.gridLayout_3.addWidget(self.trace3, 18, 0, 1, 1)
+ self.trace2 = QtWidgets.QCheckBox(self.ViewNormal)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ font.setBold(True)
+ font.setWeight(75)
+ self.trace2.setFont(font)
+ self.trace2.setTristate(False)
+ self.trace2.setObjectName("trace2")
+ self.gridLayout_3.addWidget(self.trace2, 16, 0, 1, 1)
self.trace1 = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
@@ -146,15 +198,15 @@ def setupUi(self, MainWindow):
self.trace1.setChecked(True)
self.trace1.setTristate(False)
self.trace1.setObjectName("trace1")
- self.gridLayout_3.addWidget(self.trace1, 11, 0, 1, 1)
- self.trace3 = QtWidgets.QCheckBox(self.ViewNormal)
+ self.gridLayout_3.addWidget(self.trace1, 13, 0, 1, 1)
+ self.lna_box = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
- font.setBold(True)
- font.setWeight(75)
- self.trace3.setFont(font)
- self.trace3.setObjectName("trace3")
- self.gridLayout_3.addWidget(self.trace3, 16, 0, 1, 1)
+ font.setBold(False)
+ font.setWeight(50)
+ self.lna_box.setFont(font)
+ self.lna_box.setObjectName("lna_box")
+ self.gridLayout_3.addWidget(self.lna_box, 0, 0, 1, 1)
self.battery = QtWidgets.QLabel(self.ViewNormal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
@@ -165,64 +217,9 @@ def setupUi(self, MainWindow):
font.setPointSize(7)
self.battery.setFont(font)
self.battery.setObjectName("battery")
- self.gridLayout_3.addWidget(self.battery, 25, 0, 1, 1)
- self.t3_type = QtWidgets.QComboBox(self.ViewNormal)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.t3_type.sizePolicy().hasHeightForWidth())
- self.t3_type.setSizePolicy(sizePolicy)
- font = QtGui.QFont()
- font.setPointSize(7)
- self.t3_type.setFont(font)
- self.t3_type.setObjectName("t3_type")
- self.gridLayout_3.addWidget(self.t3_type, 17, 0, 1, 1)
- self.t1_type = QtWidgets.QComboBox(self.ViewNormal)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.t1_type.sizePolicy().hasHeightForWidth())
- self.t1_type.setSizePolicy(sizePolicy)
- font = QtGui.QFont()
- font.setPointSize(7)
- self.t1_type.setFont(font)
- self.t1_type.setModelColumn(0)
- self.t1_type.setObjectName("t1_type")
- self.gridLayout_3.addWidget(self.t1_type, 12, 0, 1, 1)
- self.points_auto = QtWidgets.QCheckBox(self.ViewNormal)
- self.points_auto.setEnabled(True)
- font = QtGui.QFont()
- font.setPointSize(7)
- font.setBold(True)
- font.setWeight(75)
- self.points_auto.setFont(font)
- self.points_auto.setChecked(True)
- self.points_auto.setObjectName("points_auto")
- self.rbwpointsgroup = QtWidgets.QButtonGroup(MainWindow)
- self.rbwpointsgroup.setObjectName("rbwpointsgroup")
- self.rbwpointsgroup.addButton(self.points_auto)
- self.gridLayout_3.addWidget(self.points_auto, 9, 0, 1, 1)
- self.trace2 = QtWidgets.QCheckBox(self.ViewNormal)
- font = QtGui.QFont()
- font.setPointSize(7)
- font.setBold(True)
- font.setWeight(75)
- self.trace2.setFont(font)
- self.trace2.setTristate(False)
- self.trace2.setObjectName("trace2")
- self.gridLayout_3.addWidget(self.trace2, 14, 0, 1, 1)
- self.points_box = QtWidgets.QSpinBox(self.ViewNormal)
- font = QtGui.QFont()
- font.setPointSize(7)
- self.points_box.setFont(font)
- self.points_box.setSuffix("")
- self.points_box.setMinimum(1)
- self.points_box.setMaximum(30000)
- self.points_box.setSingleStep(100)
- self.points_box.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
- self.points_box.setProperty("value", 400)
- self.points_box.setObjectName("points_box")
- self.gridLayout_3.addWidget(self.points_box, 10, 0, 1, 1)
+ self.gridLayout_3.addWidget(self.battery, 27, 0, 1, 1)
+ spacerItem = QtWidgets.QSpacerItem(17, 13, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.gridLayout_3.addItem(spacerItem, 24, 0, 1, 1)
self.rbw_box = QtWidgets.QComboBox(self.ViewNormal)
self.rbw_box.setEnabled(True)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
@@ -236,6 +233,11 @@ def setupUi(self, MainWindow):
self.rbw_box.setEditable(True)
self.rbw_box.setObjectName("rbw_box")
self.gridLayout_3.addWidget(self.rbw_box, 8, 0, 1, 1)
+ self.line_2 = QtWidgets.QFrame(self.ViewNormal)
+ self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line_2.setObjectName("line_2")
+ self.gridLayout_3.addWidget(self.line_2, 2, 0, 1, 1)
self.rbw_auto = QtWidgets.QCheckBox(self.ViewNormal)
font = QtGui.QFont()
font.setPointSize(7)
@@ -243,13 +245,16 @@ def setupUi(self, MainWindow):
font.setWeight(75)
self.rbw_auto.setFont(font)
self.rbw_auto.setObjectName("rbw_auto")
- self.rbwpointsgroup.addButton(self.rbw_auto)
self.gridLayout_3.addWidget(self.rbw_auto, 7, 0, 1, 1)
- self.line_2 = QtWidgets.QFrame(self.ViewNormal)
- self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
- self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.line_2.setObjectName("line_2")
- self.gridLayout_3.addWidget(self.line_2, 2, 0, 1, 1)
+ self.sampleRepeat = QtWidgets.QSpinBox(self.ViewNormal)
+ font = QtGui.QFont()
+ font.setPointSize(7)
+ self.sampleRepeat.setFont(font)
+ self.sampleRepeat.setMinimum(1)
+ self.sampleRepeat.setMaximum(10000)
+ self.sampleRepeat.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
+ self.sampleRepeat.setObjectName("sampleRepeat")
+ self.gridLayout_3.addWidget(self.sampleRepeat, 12, 0, 1, 1)
self.gridLayout.addLayout(self.gridLayout_3, 0, 0, 1, 1)
self.gridLayout_2 = QtWidgets.QGridLayout()
self.gridLayout_2.setObjectName("gridLayout_2")
@@ -346,7 +351,7 @@ def setupUi(self, MainWindow):
self.avgSlider.setFont(font)
self.avgSlider.setMinimum(1)
self.avgSlider.setMaximum(101)
- self.avgSlider.setProperty("value", 10)
+ self.avgSlider.setProperty("value", 1)
self.avgSlider.setOrientation(QtCore.Qt.Horizontal)
self.avgSlider.setInvertedAppearance(False)
self.avgSlider.setInvertedControls(False)
@@ -901,12 +906,14 @@ def setupUi(self, MainWindow):
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
- self.menuBar.setGeometry(QtCore.QRect(0, 0, 1000, 23))
+ self.menuBar.setGeometry(QtCore.QRect(0, 0, 1024, 23))
self.menuBar.setObjectName("menuBar")
self.menu_Help = QtWidgets.QMenu(self.menuBar)
self.menu_Help.setObjectName("menu_Help")
self.menuSettings = QtWidgets.QMenu(self.menuBar)
self.menuSettings.setObjectName("menuSettings")
+ self.menuFile = QtWidgets.QMenu(self.menuBar)
+ self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menuBar)
self.actionsetting = QtWidgets.QAction(MainWindow)
self.actionsetting.setObjectName("actionsetting")
@@ -920,8 +927,15 @@ def setupUi(self, MainWindow):
self.actionSweeps.setObjectName("actionSweeps")
self.actionbands = QtWidgets.QAction(MainWindow)
self.actionbands.setObjectName("actionbands")
+ self.actionBrowse_TinySA = QtWidgets.QAction(MainWindow)
+ self.actionBrowse_TinySA.setObjectName("actionBrowse_TinySA")
+ self.actionQuit = QtWidgets.QAction(MainWindow)
+ self.actionQuit.setObjectName("actionQuit")
self.menu_Help.addAction(self.actionAbout_QtTinySA)
self.menuSettings.addAction(self.actionPreferences)
+ self.menuFile.addAction(self.actionBrowse_TinySA)
+ self.menuFile.addAction(self.actionQuit)
+ self.menuBar.addAction(self.menuFile.menuAction())
self.menuBar.addAction(self.menuSettings.menuAction())
self.menuBar.addAction(self.menu_Help.menuAction())
@@ -931,37 +945,38 @@ def setupUi(self, MainWindow):
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
- self.atten_auto.setToolTip(_translate("MainWindow", "Enable auto attenuator"))
- self.atten_auto.setText(_translate("MainWindow", "Auto Att"))
- self.t2_type.setToolTip(_translate("MainWindow", "Trace Type"))
- self.version.setToolTip(_translate("MainWindow", "Firmware Version"))
- self.version.setText(_translate("MainWindow", "Cnx"))
- self.spur_box.setToolTip(_translate("MainWindow", "Spur reduction - impacts scanning speed"))
- self.spur_box.setText(_translate("MainWindow", "Spurs"))
self.trace4.setToolTip(_translate("MainWindow", "Enable Trace"))
self.trace4.setText(_translate("MainWindow", "Trace 4"))
+ self.spur_box.setToolTip(_translate("MainWindow", "Spur reduction - impacts scanning speed"))
+ self.spur_box.setText(_translate("MainWindow", "Spurs"))
+ self.t2_type.setToolTip(_translate("MainWindow", "Trace Type"))
self.t4_type.setToolTip(_translate("MainWindow", "Trace Type"))
+ self.t3_type.setToolTip(_translate("MainWindow", "Trace Type"))
self.atten_box.setToolTip(_translate("MainWindow", "Set Attenuation"))
self.atten_box.setSuffix(_translate("MainWindow", "dB"))
- self.mixerMode.setText(_translate("MainWindow", "LNB"))
- self.lna_box.setToolTip(_translate("MainWindow", "Enable Low Noise Amplifier"))
- self.lna_box.setText(_translate("MainWindow", "LNA"))
- self.trace1.setToolTip(_translate("MainWindow", "Enable Trace"))
- self.trace1.setText(_translate("MainWindow", "Trace 1"))
- self.trace3.setToolTip(_translate("MainWindow", "Enable Trace"))
- self.trace3.setText(_translate("MainWindow", "Trace 3"))
- self.battery.setToolTip(_translate("MainWindow", "Battery Voltage"))
- self.battery.setText(_translate("MainWindow", "Battery"))
- self.t3_type.setToolTip(_translate("MainWindow", "Trace Type"))
+ self.version.setToolTip(_translate("MainWindow", "Firmware Version"))
+ self.version.setText(_translate("MainWindow", "Cnx"))
self.t1_type.setToolTip(_translate("MainWindow", "Trace Type"))
+ self.points_box.setToolTip(_translate("MainWindow", "Set the number of frequency Points to measure"))
self.points_auto.setToolTip(_translate("MainWindow", "Auto set points to suit RBW"))
self.points_auto.setText(_translate("MainWindow", "Auto Pts"))
+ self.mixerMode.setText(_translate("MainWindow", "LNB"))
+ self.atten_auto.setToolTip(_translate("MainWindow", "Enable auto attenuator"))
+ self.atten_auto.setText(_translate("MainWindow", "Auto Att"))
+ self.trace3.setToolTip(_translate("MainWindow", "Enable Trace"))
+ self.trace3.setText(_translate("MainWindow", "Trace 3"))
self.trace2.setToolTip(_translate("MainWindow", "Enable Trace"))
self.trace2.setText(_translate("MainWindow", "Trace 2"))
- self.points_box.setToolTip(_translate("MainWindow", "Set Points"))
+ self.trace1.setToolTip(_translate("MainWindow", "Enable Trace"))
+ self.trace1.setText(_translate("MainWindow", "Trace 1"))
+ self.lna_box.setToolTip(_translate("MainWindow", "Enable Low Noise Amplifier"))
+ self.lna_box.setText(_translate("MainWindow", "LNA"))
+ self.battery.setToolTip(_translate("MainWindow", "Battery Voltage"))
+ self.battery.setText(_translate("MainWindow", "Battery"))
self.rbw_box.setToolTip(_translate("MainWindow", "Set Resolution Bandwidth"))
self.rbw_auto.setToolTip(_translate("MainWindow", "Enable Auto Resolution Bandwidth"))
self.rbw_auto.setText(_translate("MainWindow", "Auto RBW"))
+ self.sampleRepeat.setToolTip(_translate("MainWindow", "Set the number of repeat measurements at each frequency Point"))
self.mkr_start.setToolTip(_translate("MainWindow", "Set markers to start frequency"))
self.mkr_start.setText(_translate("MainWindow", "..."))
self.stop_freq.setToolTip(_translate("MainWindow", "Sweep Stop"))
@@ -972,7 +987,7 @@ def retranslateUi(self, MainWindow):
self.mkr_centre.setToolTip(_translate("MainWindow", "Set markers in range"))
self.mkr_centre.setText(_translate("MainWindow", "..."))
self.avgSlider.setToolTip(_translate("MainWindow", "Averaging"))
- self.mToBand.setToolTip(_translate("MainWindow", "Add Band preset from M1 and M2"))
+ self.mToBand.setToolTip(_translate("MainWindow", "Use M1 to add Marker, or M1 and M2 to add Band"))
self.mToBand.setText(_translate("MainWindow", "+"))
self.filterBox.setToolTip(_translate("MainWindow", "Filter preset list"))
self.centre_freq.setToolTip(_translate("MainWindow", "Sweep Centre"))
@@ -1022,11 +1037,14 @@ def retranslateUi(self, MainWindow):
self.grid.setText(_translate("MainWindow", "Show Grid"))
self.menu_Help.setTitle(_translate("MainWindow", "&Help"))
self.menuSettings.setTitle(_translate("MainWindow", "&Settings"))
+ self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionsetting.setText(_translate("MainWindow", "setting"))
self.actionlevel.setText(_translate("MainWindow", "level"))
self.actionAbout_QtTinySA.setText(_translate("MainWindow", "About QtTinySA"))
self.actionPreferences.setText(_translate("MainWindow", "Preferences"))
self.actionSweeps.setText(_translate("MainWindow", "Sweeps"))
self.actionbands.setText(_translate("MainWindow", "Bands and Markers"))
+ self.actionBrowse_TinySA.setText(_translate("MainWindow", "Browse TinySA"))
+ self.actionQuit.setText(_translate("MainWindow", "Quit"))
from pyqtgraph import PlotWidget
from pyqtgraph.opengl import GLViewWidget
diff --git a/QtTinySpectrum.ui b/QtTinySpectrum.ui
index b7814d7..b46da7d 100644
--- a/QtTinySpectrum.ui
+++ b/QtTinySpectrum.ui
@@ -7,8 +7,8 @@
0
0
- 1000
- 603
+ 1024
+ 614
@@ -43,45 +43,45 @@
-
-
-
-
+
-
+
7
+ 75
+ true
-
- Qt::Vertical
+
+ Enable Trace
-
-
- 17
- 13
-
+
+ Trace 4
-
+
- -
-
+
-
+
7
- 75
- true
- Enable auto attenuator
+ Spur reduction - impacts scanning speed
- Auto Att
+ Spurs
true
+
+ true
+
- -
+
-
@@ -99,10 +99,10 @@
- -
-
+
-
+
-
+
0
0
@@ -113,53 +113,81 @@
- Firmware Version
+ Trace Type
-
- Cnx
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 7
+
+
+
+ Trace Type
- -
-
+
-
+
+
+ false
+
7
- Spur reduction - impacts scanning speed
+ Set Attenuation
-
- Spurs
+
+ false
-
- true
+
+ dB
-
- true
+
+ 0
+
+
+ 31
+
+
+ 0
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
7
- 75
- true
- Enable Trace
+ Firmware Version
- Trace 4
+ Cnx
- -
-
+
-
+
0
@@ -174,39 +202,65 @@
Trace Type
+
+ 0
+
- -
-
-
- false
-
+
-
+
7
- Set Attenuation
-
-
- false
+ Set the number of frequency Points to measure
- dB
+
- 0
+ 1
- 31
+ 30000
+
+
+ 100
+
+
+ QAbstractSpinBox::AdaptiveDecimalStepType
- 0
+ 400
- -
+
-
+
+
+ true
+
+
+
+ 7
+ 75
+ true
+
+
+
+ Auto set points to suit RBW
+
+
+ Auto Pts
+
+
+ true
+
+
+
+ -
@@ -251,25 +305,8 @@
- -
-
-
-
- 7
- 50
- false
-
-
-
- Enable Low Noise Amplifier
-
-
- LNA
-
-
-
- -
-
+
-
+
7
@@ -278,20 +315,17 @@
- Enable Trace
+ Enable auto attenuator
- Trace 1
+ Auto Att
true
-
- false
-
- -
+
-
@@ -308,141 +342,104 @@
- -
-
-
-
- 0
- 0
-
-
+
-
+
7
+ 75
+ true
- Battery Voltage
+ Enable Trace
- Battery
+ Trace 2
+
+
+ false
- -
-
-
-
- 0
- 0
-
-
+
-
+
7
+ 75
+ true
- Trace Type
-
-
-
- -
-
-
-
- 0
- 0
-
+ Enable Trace
-
-
- 7
-
+
+ Trace 1
-
- Trace Type
+
+ true
-
- 0
+
+ false
- -
-
-
- true
-
+
-
+
7
- 75
- true
+ 50
+ false
- Auto set points to suit RBW
+ Enable Low Noise Amplifier
- Auto Pts
-
-
- true
+ LNA
-
- rbwpointsgroup
-
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
7
- 75
- true
- Enable Trace
+ Battery Voltage
- Trace 2
-
-
- false
+ Battery
- -
-
+
-
+
7
-
- Set Points
-
-
-
-
-
- 1
-
-
- 30000
-
-
- 100
-
-
- QAbstractSpinBox::AdaptiveDecimalStepType
+
+ Qt::Vertical
-
- 400
+
+
+ 17
+ 13
+
-
+
-
@@ -468,6 +465,13 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
-
@@ -483,15 +487,26 @@
Auto RBW
-
- rbwpointsgroup
-
- -
-
-
- Qt::Horizontal
+
-
+
+
+
+ 7
+
+
+
+ Set the number of repeat measurements at each frequency Point
+
+
+ 1
+
+
+ 10000
+
+
+ QAbstractSpinBox::AdaptiveDecimalStepType
@@ -715,7 +730,7 @@
101
- 10
+ 1
Qt::Horizontal
@@ -742,7 +757,7 @@
- Add Band preset from M1 and M2
+ Use M1 to add Marker, or M1 and M2 to add Band
+
@@ -1930,7 +1945,7 @@
0
0
- 1000
+ 1024
23
@@ -1946,6 +1961,14 @@
+
+
@@ -1979,6 +2002,16 @@
Bands and Markers
+
+
+ Browse TinySA
+
+
+
+
+ Quit
+
+
@@ -2012,7 +2045,4 @@
true
-
-
-
diff --git a/Screenshots/3D_20240418_103532.png b/Screenshots/3D_20240418_103532.png
new file mode 100644
index 0000000..ae646e7
Binary files /dev/null and b/Screenshots/3D_20240418_103532.png differ
diff --git a/Screenshots/3D_20240418_103613.png b/Screenshots/3D_20240418_103613.png
new file mode 100644
index 0000000..a745214
Binary files /dev/null and b/Screenshots/3D_20240418_103613.png differ
diff --git a/Screenshots/tv_channels.png b/Screenshots/tv_channels.png
new file mode 100644
index 0000000..42efa5d
Binary files /dev/null and b/Screenshots/tv_channels.png differ
diff --git a/filebrowse.ui b/filebrowse.ui
new file mode 100644
index 0000000..d041750
--- /dev/null
+++ b/filebrowse.ui
@@ -0,0 +1,84 @@
+
+
+ Filebrowse
+
+
+
+ 0
+ 0
+ 818
+ 405
+
+
+
+ File List
+
+
+
+
+ 10
+ 20
+ 301
+ 311
+
+
+
+
+
+
+ 10
+ 350
+ 80
+ 26
+
+
+
+ Save
+
+
+
+
+
+ 320
+ 20
+ 481
+ 321
+
+
+
+
+
+
+ false
+
+
+
+
+
+ 100
+ 350
+ 211
+ 26
+
+
+
+ 0
+
+
+
+
+
+ 10
+ 380
+ 791
+ 20
+
+
+
+
+
+
+
+
+
+
diff --git a/preferences.ui b/preferences.ui
index 128a4c9..fd4cb26 100644
--- a/preferences.ui
+++ b/preferences.ui
@@ -6,7 +6,7 @@
0
0
- 800
+ 817
600
@@ -156,46 +156,13 @@
440
10
- 356
+ 361
571
- -
-
-
- 0dBm
-
-
- false
-
-
-
- -
-
-
- Points / Resolution Bandwidth
-
-
-
- -
-
-
- QAbstractSpinBox::NoButtons
-
-
- 25
-
-
- 450
-
-
- 450
-
-
-
- -
-
+
-
+
75
@@ -203,100 +170,49 @@
- External Mixer / LNB
+ Miscellaneous
-
-
-
-
- 0
- 0
-
-
-
-
- 83
- 16777215
-
-
-
-
- 9
-
-
-
- dBm
-
-
-
-
+
- -120
+ 2
- -20
+ 10
- -90
+ 3
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- MHz
-
-
- 6
-
-
- 0.000000000000000
-
-
- 100000.000000000000000
-
-
- 0.000000000000000
+
-
+
+
+ Sync to PC
- -
-
-
- 2
-
-
- 10
+
-
+
+
+ +6dBm
-
- 3
+
+ false
- -
-
+
-
+
- Auto maximum points
+ Points / Resolution Bandwidth
- -
-
+
-
+
75
@@ -304,7 +220,30 @@
- Scan Points Settings
+ External Mixer / LNB
+
+
+
+ -
+
+
+ Absolute maximum
+
+
+
+ -
+
+
+ QAbstractSpinBox::NoButtons
+
+
+ 25
+
+
+ 100000
+
+
+ 30000
@@ -321,6 +260,13 @@
+ -
+
+
+ Max with auto attenuator
+
+
+
-
@@ -331,10 +277,24 @@
- -
-
+
-
+
- Absolute maximum
+ Peak marker detection threshold
+
+
+
+ -
+
+
+ Auto maximum points
+
+
+
+ -
+
+
+ True
@@ -345,62 +305,75 @@
- -
+
-
LO above displayed Freq
- -
-
+
-
+
- +6dBm
+ 0dBm
false
- -
-
+
-
+
-
+ Auto minimum points
- -
-
+
-
+
- Detection Threshold
+ LO Frequency
- -
-
-
- Max with auto attenuator
+
-
+
+
+
+ 0
+ 0
+
-
-
- -
-
-
- QAbstractSpinBox::NoButtons
+
+
+ 83
+ 16777215
+
+
+
+
+ 9
+
+
+
+ dBm
+
+
+
- 25
+ -120
- 100000
+ -20
- 30000
+ -90
-
-
+
75
@@ -408,28 +381,62 @@
- Peak Marker Settings
+ Scan Points Settings
- -
-
-
- Auto minimum points
+
-
+
+
+ QAbstractSpinBox::NoButtons
+
+
+ 25
+
+
+ 450
+
+
+ 450
- -
-
-
- LO Frequency
+
-
+
+
+ MHz
+
+
+ 6
+
+
+ 0.000000000000000
+
+
+ 100000.000000000000000
+
+
+ 0.000000000000000
- -
-
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
- True
+ Date and Time