forked from NanoVNA-Saver/nanovna-saver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHardware.py
154 lines (138 loc) · 5 KB
/
Hardware.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# 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
import platform
from collections import namedtuple
from time import sleep
from typing import List
import serial
from serial.tools import list_ports
from NanoVNASaver.Hardware.AVNA import AVNA
from NanoVNASaver.Hardware.NanoVNA import NanoVNA
from NanoVNASaver.Hardware.NanoVNA_F import NanoVNA_F
from NanoVNASaver.Hardware.NanoVNA_F_V2 import NanoVNA_F_V2
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__)
USBDevice = namedtuple("Device", "vid pid name")
USBDEVICETYPES = (
USBDevice(0x0483, 0x5740, "NanoVNA"),
USBDevice(0x16c0, 0x0483, "AVNA"),
USBDevice(0x04b4, 0x0008, "S-A-A-2"),
)
RETRIES = 3
TIMEOUT = 0.2
WAIT = 0.05
# The USB Driver for NanoVNA V2 seems to deliver an
# incompatible hardware info like:
# 'PORTS\\VID_04B4&PID_0008\\DEMO'
# This function will fix it.
def _fix_v2_hwinfo(dev):
if dev.hwid == r'PORTS\VID_04B4&PID_0008\DEMO':
dev.vid, dev.pid = 0x04b4, 0x0008
return dev
# Get list of interfaces with VNAs connected
def get_interfaces() -> List[Interface]:
interfaces = []
# serial like usb interfaces
for d in list_ports.comports():
if platform.system() == 'Windows' and d.vid is None:
d = _fix_v2_hwinfo(d)
for t in USBDEVICETYPES:
if d.vid != t.vid or d.pid != t.pid:
continue
logger.debug("Found %s USB:(%04x:%04x) on port %s",
t.name, d.vid, d.pid, d.device)
iface = Interface('serial', t.name)
iface.port = d.device
interfaces.append(iface)
return interfaces
def get_VNA(iface: Interface) -> 'VNA':
# serial_port.timeout = TIMEOUT
logger.info("Finding correct VNA type...")
with iface.lock:
vna_version = detect_version(iface)
if vna_version == 'v2':
logger.info("Type: NanoVNA-V2")
return NanoVNA_V2(iface)
logger.info("Finding firmware variant...")
info = get_info(iface)
if info.find("AVNA + Teensy") >= 0:
logger.info("Type: AVNA")
return AVNA(iface)
if info.find("NanoVNA-H 4") >= 0:
logger.info("Type: NanoVNA-H4")
vna = NanoVNA_H4(iface)
return vna
if info.find("NanoVNA-H") >= 0:
logger.info("Type: NanoVNA-H")
vna = NanoVNA_H(iface)
return vna
if info.find("NanoVNA-F_V2") >= 0:
logger.info("Type: NanoVNA-F_V2")
return NanoVNA_F_V2(iface)
if info.find("NanoVNA-F") >= 0:
logger.info("Type: NanoVNA-F")
return NanoVNA_F(iface)
if info.find("NanoVNA") >= 0:
logger.info("Type: Generic NanoVNA")
return NanoVNA(iface)
logger.warning("Did not recognize NanoVNA type from firmware.")
return NanoVNA(iface)
def detect_version(serial_port: serial.Serial) -> str:
data = ""
for i in range(RETRIES):
drain_serial(serial_port)
serial_port.write("\r".encode("ascii"))
sleep(0.05)
data = serial_port.read(128).decode("ascii")
if data.startswith("ch> "):
return "v1"
# -H versions
if data.startswith("\r\nch> "):
return "vh"
if data.startswith("2"):
return "v2"
logger.debug("Retry detection: %s", i + 1)
logger.error('No VNA detected. Hardware responded to CR with: %s', data)
return ""
def get_info(serial_port: serial.Serial) -> str:
for _ in range(RETRIES):
drain_serial(serial_port)
serial_port.write("info\r".encode("ascii"))
lines = []
retries = 0
while True:
line = serial_port.readline()
line = line.decode("ascii").strip()
if not line:
retries += 1
if retries > RETRIES:
return ""
sleep(WAIT)
continue
if line == "info": # suppress echo
continue
if line.startswith("ch>"):
logger.debug("Needed retries: %s", retries)
break
lines.append(line)
return "\n".join(lines)