kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Fix custom datapoints on H4
rodzic
496494900f
commit
948c04f154
|
@ -26,10 +26,11 @@ from serial.tools import list_ports
|
|||
|
||||
from NanoVNASaver.Hardware.VNA import VNA
|
||||
from NanoVNASaver.Hardware.AVNA import AVNA
|
||||
from NanoVNASaver.Hardware.NanoVNA_F import NanoVNA_F
|
||||
from NanoVNASaver.Hardware.NanoVNA_H import NanoVNA_H, NanoVNA_H4
|
||||
from NanoVNASaver.Hardware.NanoVNA import NanoVNA
|
||||
from NanoVNASaver.Hardware.NanoVNA_V2 import NanoVNAV2
|
||||
from NanoVNASaver.Hardware.NanoVNA_F import NanoVNA_F
|
||||
from NanoVNASaver.Hardware.NanoVNA_H import NanoVNA_H
|
||||
from NanoVNASaver.Hardware.NanoVNA_H4 import NanoVNA_H4
|
||||
from NanoVNASaver.Hardware.NanoVNA_V2 import NanoVNA_V2
|
||||
from NanoVNASaver.Hardware.Serial import drain_serial, Interface
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -82,7 +83,7 @@ def get_VNA(iface: Interface) -> 'VNA':
|
|||
|
||||
if vna_version == 'v2':
|
||||
logger.info("Type: NanoVNA-V2")
|
||||
return NanoVNAV2(iface)
|
||||
return NanoVNA_V2(iface)
|
||||
|
||||
logger.info("Finding firmware variant...")
|
||||
tmp_vna = VNA(iface)
|
||||
|
@ -94,16 +95,10 @@ def get_VNA(iface: Interface) -> 'VNA':
|
|||
if firmware.find("NanoVNA-H 4") > 0:
|
||||
logger.info("Type: NanoVNA-H4")
|
||||
vna = NanoVNA_H4(iface)
|
||||
if vna.readFirmware().find("sweep_points 201") > 0:
|
||||
logger.info("VNA has 201 datapoints capability")
|
||||
vna.datapoints = (201, 101)
|
||||
return vna
|
||||
if firmware.find("NanoVNA-H") > 0:
|
||||
logger.info("Type: NanoVNA-H")
|
||||
vna = NanoVNA_H(iface)
|
||||
if vna.readFirmware().find("sweep_points 201") > 0:
|
||||
logger.info("VNA has 201 datapoints capability")
|
||||
vna.datapoints = (201, 101)
|
||||
return vna
|
||||
if firmware.find("NanoVNA-F") > 0:
|
||||
logger.info("Type: NanoVNA-F")
|
||||
|
|
|
@ -45,15 +45,6 @@ class NanoVNA(VNA):
|
|||
self.stop = 30000000
|
||||
self._sweepdata = []
|
||||
|
||||
if self.version >= Version("0.7.1"):
|
||||
self.features.add("Scan mask command")
|
||||
self.sweep_method = "scan_mask"
|
||||
elif self.version >= Version("0.2.0"):
|
||||
logger.debug("Newer than 0.2.0, using new scan command.")
|
||||
self.features.add("Scan command")
|
||||
self.sweep_method = "scan"
|
||||
self.readFeatures()
|
||||
|
||||
def isValid(self):
|
||||
return True
|
||||
|
||||
|
@ -107,6 +98,17 @@ class NanoVNA(VNA):
|
|||
elif self.sweep_method == "scan":
|
||||
self.writeSerial(f"scan {start} {stop} {self.datapoints}")
|
||||
|
||||
def read_features(self):
|
||||
if self.version >= Version("0.7.1"):
|
||||
self.features.add("Scan mask command")
|
||||
self.sweep_method = "scan_mask"
|
||||
elif self.version >= Version("0.2.0"):
|
||||
logger.debug("Newer than 0.2.0, using new scan command.")
|
||||
self.features.add("Scan command")
|
||||
self.sweep_method = "scan"
|
||||
super().read_features()
|
||||
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
if self.sweep_method != "scan_mask":
|
||||
return super().readFrequencies()
|
||||
|
|
|
@ -26,8 +26,10 @@ logger = logging.getLogger(__name__)
|
|||
class NanoVNA_H(NanoVNA):
|
||||
name = "NanoVNA-H"
|
||||
|
||||
|
||||
class NanoVNA_H4(NanoVNA):
|
||||
name = "NanoVNA-H4"
|
||||
screenwidth = 480
|
||||
screenheight = 320
|
||||
def read_features(self):
|
||||
logger.debug("read_features")
|
||||
if self.readFirmware().find("sweep_points 201") > 0:
|
||||
logger.info("VNA has 201 datapoints capability")
|
||||
self.valid_datapoints = (201, 101)
|
||||
self.datapoints = 201
|
||||
super().read_features()
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# NanoVNASaver
|
||||
#
|
||||
# A python program to view and export Touchstone data from a NanoVNA
|
||||
# Copyright (C) 2020 NanoVNA-Saver Authors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
|
||||
from NanoVNASaver.Hardware.NanoVNA_H import NanoVNA_H
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NanoVNA_H4(NanoVNA_H):
|
||||
name = "NanoVNA-H4"
|
||||
screenwidth = 480
|
||||
screenheight = 320
|
|
@ -19,6 +19,7 @@
|
|||
import logging
|
||||
import platform
|
||||
from struct import pack, unpack_from
|
||||
from time import sleep
|
||||
from typing import List
|
||||
|
||||
from NanoVNASaver.Hardware.Serial import Interface
|
||||
|
@ -54,9 +55,9 @@ _ADDR_FW_MAJOR = 0xf3
|
|||
_ADDR_FW_MINOR = 0xf4
|
||||
|
||||
|
||||
class NanoVNAV2(VNA):
|
||||
class NanoVNA_V2(VNA):
|
||||
name = "NanoVNA-V2"
|
||||
_datapoints = (303, 101, 203, 505, 1023)
|
||||
valid_datapoints = (202, 101, 303, 505, 1023)
|
||||
screenwidth = 320
|
||||
screenheight = 240
|
||||
|
||||
|
@ -72,9 +73,6 @@ class NanoVNAV2(VNA):
|
|||
|
||||
self.version = self.readVersion()
|
||||
self.firmware = self.readFirmware()
|
||||
self.features.add("Customizable data points")
|
||||
# TODO: more than one dp per freq
|
||||
self.features.add("Multi data points")
|
||||
|
||||
# firmware major version of 0xff indicates dfu mode
|
||||
if self.firmware.data["major"] == 0xff:
|
||||
|
@ -84,11 +82,15 @@ class NanoVNAV2(VNA):
|
|||
self.sweepStepHz = 1e6
|
||||
self._sweepdata = []
|
||||
self._updateSweep()
|
||||
# self.setSweep(200e6, 300e6)
|
||||
|
||||
def getCalibration(self) -> str:
|
||||
return "Unknown"
|
||||
|
||||
def read_features(self):
|
||||
self.features.add("Customizable data points")
|
||||
# TODO: more than one dp per freq
|
||||
self.features.add("Multi data points")
|
||||
|
||||
def readFirmware(self) -> str:
|
||||
# read register 0xf3 and 0xf4 (firmware major and minor version)
|
||||
cmd = pack("<BBBB",
|
||||
|
@ -96,6 +98,7 @@ class NanoVNAV2(VNA):
|
|||
_CMD_READ, _ADDR_FW_MINOR)
|
||||
with self.serial.lock:
|
||||
self.serial.write(cmd)
|
||||
sleep(0.05)
|
||||
resp = self.serial.read(2)
|
||||
if len(resp) != 2:
|
||||
logger.error("Timeout reading version registers")
|
||||
|
@ -130,7 +133,7 @@ class NanoVNAV2(VNA):
|
|||
pack("<BBB",
|
||||
_CMD_READFIFO, _ADDR_VALUES_FIFO,
|
||||
pointstoread))
|
||||
|
||||
sleep(0.05)
|
||||
# each value is 32 bytes
|
||||
nBytes = pointstoread * 32
|
||||
|
||||
|
@ -141,6 +144,7 @@ class NanoVNAV2(VNA):
|
|||
nBytes, len(arr))
|
||||
return []
|
||||
|
||||
freq_index = -1
|
||||
for i in range(pointstoread):
|
||||
(fwd_real, fwd_imag, rev0_real, rev0_imag, rev1_real,
|
||||
rev1_imag, freq_index) = unpack_from(
|
||||
|
@ -148,8 +152,10 @@ class NanoVNAV2(VNA):
|
|||
fwd = complex(fwd_real, fwd_imag)
|
||||
refl = complex(rev0_real, rev0_imag)
|
||||
thru = complex(rev1_real, rev1_imag)
|
||||
logger.debug("Freq index: %i", freq_index)
|
||||
if i == 0:
|
||||
logger.debug("Freq index from: %i", freq_index)
|
||||
self._sweepdata[freq_index] = (refl / fwd, thru / fwd)
|
||||
logger.debug("Freq index to: %i", freq_index)
|
||||
|
||||
pointstodo = pointstodo - pointstoread
|
||||
|
||||
|
|
|
@ -24,10 +24,12 @@ import serial
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
def drain_serial(serial_port: serial.Serial):
|
||||
"""drain up to 10k outstanding data in the serial incoming buffer"""
|
||||
for _ in range(80):
|
||||
if len(serial_port.read(128)) == 0:
|
||||
break
|
||||
"""drain up to 64k outstanding data in the serial incoming buffer"""
|
||||
for _ in range(512):
|
||||
cnt = len(serial_port.read(128))
|
||||
if not cnt:
|
||||
return
|
||||
logger.warning("unable to drain all data")
|
||||
|
||||
class Interface(serial.Serial):
|
||||
def __init__(self, interface_type: str, comment, *args, **kwargs):
|
||||
|
|
|
@ -31,16 +31,17 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
class VNA:
|
||||
name = "VNA"
|
||||
_datapoints = (101, )
|
||||
valid_datapoints = (101, )
|
||||
|
||||
def __init__(self, iface: Interface):
|
||||
self.serial = iface
|
||||
self.version = Version("0.0.0")
|
||||
self.features = set()
|
||||
self.validateInput = True
|
||||
self.datapoints = VNA._datapoints[0]
|
||||
self.datapoints = self.valid_datapoints[0]
|
||||
self.read_features()
|
||||
|
||||
def readFeatures(self) -> List[str]:
|
||||
def read_features(self):
|
||||
raw_help = self.readFromCommand("help")
|
||||
logger.debug("Help command output:")
|
||||
logger.debug(raw_help)
|
||||
|
@ -48,11 +49,9 @@ class VNA:
|
|||
# Detect features from the help command
|
||||
if "capture" in raw_help:
|
||||
self.features.add("Screenshots")
|
||||
if len(self._datapoints) > 1:
|
||||
if len(self.valid_datapoints) > 1:
|
||||
self.features.add("Customizable data points")
|
||||
|
||||
return self.features
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
return [int(f) for f in self.readValues("frequencies")]
|
||||
|
||||
|
|
|
@ -125,8 +125,7 @@ class DeviceSettingsWindow(QtWidgets.QWidget):
|
|||
if "Customizable data points" in features:
|
||||
self.datapoints.clear()
|
||||
cur_dps = self.app.vna.datapoints
|
||||
dplist = self.app.vna._datapoints[:]
|
||||
for d in sorted(dplist):
|
||||
for d in sorted(self.app.vna.valid_datapoints):
|
||||
self.datapoints.addItem(str(d))
|
||||
self._set_datapoint_index(cur_dps)
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class SweepSettingsWindow(QtWidgets.QWidget):
|
|||
"Averaging allows discarding outlying samples to get better averages."))
|
||||
settings_layout.addRow(
|
||||
QtWidgets.QLabel("Common values are 3/0, 5/2, 9/4 and 25/6."))
|
||||
|
||||
|
||||
self.s21att = QtWidgets.QLineEdit("0")
|
||||
|
||||
settings_layout.addRow(QtWidgets.QLabel(""))
|
||||
|
@ -158,20 +158,16 @@ class SweepSettingsWindow(QtWidgets.QWidget):
|
|||
f" to {format_frequency_short(stop)}")
|
||||
|
||||
def setS21Attenuator(self):
|
||||
|
||||
try:
|
||||
s21att = float(self.s21att.text())
|
||||
except:
|
||||
except ValueError:
|
||||
s21att = 0
|
||||
|
||||
if (s21att < 0):
|
||||
if s21att < 0:
|
||||
logger.warning("Values for attenuator are absolute and with no minus sign, resetting.")
|
||||
self.s21att.setText("0")
|
||||
else:
|
||||
logger.info("Setting an attenuator of %.2f dB inline with the CH1/S21 input", s21att)
|
||||
self.app.s21att = s21att
|
||||
|
||||
|
||||
self.app.s21att = 0
|
||||
logger.info("Setting an attenuator of %.2f dB inline with the CH1/S21 input", s21att)
|
||||
self.app.s21att = s21att
|
||||
|
||||
def setBandSweep(self):
|
||||
index_start = self.band_list.model().index(self.band_list.currentIndex(), 1)
|
||||
|
|
Ładowanie…
Reference in New Issue