quarchpy 2.1.20.dev2__py2.py3-none-any.whl → 2.1.20.dev3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quarchpy/.idea/.name +1 -1
- quarchpy/.idea/inspectionProfiles/Project_Default.xml +26 -0
- quarchpy/.idea/modules.xml +0 -1
- quarchpy/.idea/quarchpy.iml +1 -4
- quarchpy/.idea/workspace.xml +21 -226
- quarchpy/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/__pycache__/_version.cpython-311.pyc +0 -0
- quarchpy/__pycache__/connection.cpython-311.pyc +0 -0
- quarchpy/__pycache__/run.cpython-311.pyc +0 -0
- quarchpy/_version.py +1 -1
- quarchpy/config_files/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/config_files/__pycache__/quarch_config_parser.cpython-311.pyc +0 -0
- quarchpy/connection_specific/QPS/qis/help.txt +12 -4
- quarchpy/connection_specific/QPS/qis/qis.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/CInterface-1.7.8.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/Collections-2.4.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/Desktop-1.1.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/Executor-3.13.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/JNA-1.2.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/OS-1.8.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/QuarchCommon-0.2.9.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/SystemTray-4.4.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/Updates-1.1.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/Utilities-1.46.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/commons-csv-1.8.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/javassist-3.29.2-GA.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/jna-jpms-5.12.1.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/jna-platform-jpms-5.12.1.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/kotlin-stdlib-1.9.21.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-api-2.0.9.jar +0 -0
- quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-simple-2.0.9.jar +0 -0
- quarchpy/connection_specific/QPS/qis/resources/filters/Example.txt +36 -0
- quarchpy/connection_specific/QPS/qis/resources/filters/filters.csv +1004 -0
- quarchpy/connection_specific/QPS/qis/resources/filters/iec_filters.xml +26 -0
- quarchpy/connection_specific/QPS/qis/resources/filters/iec_filters.xml.bak +26 -0
- quarchpy/connection_specific/QPS/qps.jar +0 -0
- quarchpy/connection_specific/QPS/qps_lib/QuarchCommon-0.2.9.jar +0 -0
- quarchpy/connection_specific/QPS/qps_lib/commons-lang3-3.12.0.jar +0 -0
- quarchpy/connection_specific/QPS/qps_lib/opencsv-5.9.jar +0 -0
- quarchpy/connection_specific/QPS/qps_lib/qis-1.40.jar +0 -0
- quarchpy/connection_specific/QPS/scriptCommands.txt +2 -2
- quarchpy/connection_specific/__pycache__/StreamChannels.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_QIS.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_QPS.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_ReST.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_Serial.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_TCP.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_Telnet.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_USB.cpython-311.pyc +0 -0
- quarchpy/connection_specific/__pycache__/connection_mDNS.cpython-311.pyc +0 -0
- quarchpy/connection_specific/connection_QIS.py +5 -3
- quarchpy/connection_specific/connection_QIS.py.bak +1738 -0
- quarchpy/connection_specific/serial/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/__pycache__/serialutil.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/__pycache__/serialwin32.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/__pycache__/win32.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/tools/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/tools/__pycache__/list_ports.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/tools/__pycache__/list_ports_common.cpython-311.pyc +0 -0
- quarchpy/connection_specific/serial/tools/__pycache__/list_ports_windows.cpython-311.pyc +0 -0
- quarchpy/connection_specific/usb_libs/__pycache__/libusb1.cpython-311.pyc +0 -0
- quarchpy/connection_specific/usb_libs/__pycache__/usb1.cpython-311.pyc +0 -0
- quarchpy/debug/TextScanIP.py +11 -0
- quarchpy/debug/__pycache__/SystemTest.cpython-311.pyc +0 -0
- quarchpy/debug/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/debug/__pycache__/module_debug.cpython-311.pyc +0 -0
- quarchpy/debug/__pycache__/simple_terminal.cpython-311.pyc +0 -0
- quarchpy/debug/__pycache__/upgrade_quarchpy.cpython-311.pyc +0 -0
- quarchpy/debug/__pycache__/versionCompare.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/device.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/quarchArray.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/quarchPPM.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/quarchQPS.cpython-311.pyc +0 -0
- quarchpy/device/__pycache__/scanDevices.cpython-311.pyc +0 -0
- quarchpy/device/device.py.bak +504 -0
- quarchpy/device/quarchPPM.py.bak +67 -0
- quarchpy/device/quarchQPS.py.bak +396 -0
- quarchpy/device/scanDevices.py.bak +130 -108
- quarchpy/disk_test/__pycache__/AbsDiskFinder.cpython-311.pyc +0 -0
- quarchpy/disk_test/__pycache__/DiskTargetSelection.cpython-311.pyc +0 -0
- quarchpy/disk_test/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/disk_test/__pycache__/iometerDiskFinder.cpython-311.pyc +0 -0
- quarchpy/docs/CHANGES.rst.bak +4 -2
- quarchpy/docs/_build/doctrees/CHANGES.doctree +0 -0
- quarchpy/docs/_build/doctrees/environment.pickle +0 -0
- quarchpy/docs/_build/doctrees/source/changelog.doctree +0 -0
- quarchpy/docs/_build/doctrees/source/quarchpy.fio.doctree +0 -0
- quarchpy/docs/_build/html/CHANGES.html +121 -113
- quarchpy/docs/_build/html/_sources/CHANGES.rst.txt +6 -1
- quarchpy/docs/_build/html/_static/alabaster.css +14 -9
- quarchpy/docs/_build/html/_static/basic.css +1 -1
- quarchpy/docs/_build/html/_static/pygments.css +1 -1
- quarchpy/docs/_build/html/genindex.html +9 -27
- quarchpy/docs/_build/html/index.html +62 -60
- quarchpy/docs/_build/html/objects.inv +0 -0
- quarchpy/docs/_build/html/py-modindex.html +7 -11
- quarchpy/docs/_build/html/readme.html +7 -6
- quarchpy/docs/_build/html/search.html +7 -6
- quarchpy/docs/_build/html/searchindex.js +1 -1
- quarchpy/docs/_build/html/source/changelog.html +176 -167
- quarchpy/docs/_build/html/source/licenses.html +7 -6
- quarchpy/docs/_build/html/source/modules.html +8 -7
- quarchpy/docs/_build/html/source/quarchpy.calibration.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.config_files.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.connection_specific.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.debug.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.device.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.disk_test.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.fio.html +9 -34
- quarchpy/docs/_build/html/source/quarchpy.html +8 -16
- quarchpy/docs/_build/html/source/quarchpy.iometer.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.qis.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.qps.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.user_interface.html +7 -6
- quarchpy/docs/_build/html/source/quarchpy.utilities.html +7 -6
- quarchpy/docs/_build/html/source/readme.html +7 -6
- quarchpy/fio/__pycache__/FIO_interface.cpython-311.pyc +0 -0
- quarchpy/fio/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/fio/__pycache__/fioDiskFinder.cpython-311.pyc +0 -0
- quarchpy/iometer/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/iometer/__pycache__/gen_iometer_template.cpython-311.pyc +0 -0
- quarchpy/iometer/__pycache__/iometerFuncs.cpython-311.pyc +0 -0
- quarchpy/qis/__pycache__/StreamHeaderInfo.cpython-311.pyc +0 -0
- quarchpy/qis/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/qis/__pycache__/qisFuncs.cpython-311.pyc +0 -0
- quarchpy/qps/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/qps/__pycache__/qpsFuncs.cpython-311.pyc +0 -0
- quarchpy/qps/qpsFuncs.py.bak +28 -68
- quarchpy/user_interface/__pycache__/__init__.cpython-311.pyc +0 -0
- quarchpy/user_interface/__pycache__/user_interface.cpython-311.pyc +0 -0
- quarchpy/user_interface/user_interface.py.bak +749 -0
- quarchpy/utilities/TestCenter.py.bak +150 -0
- quarchpy/utilities/__pycache__/BitManipulation.cpython-311.pyc +0 -0
- quarchpy/utilities/__pycache__/TestCenter.cpython-311.pyc +0 -0
- quarchpy/utilities/__pycache__/TimeValue.cpython-311.pyc +0 -0
- quarchpy/utilities/__pycache__/Version.cpython-311.pyc +0 -0
- quarchpy/utilities/__pycache__/__init__.cpython-311.pyc +0 -0
- {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/METADATA +1 -1
- {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/RECORD +143 -114
- quarchpy/_version.py.bak +0 -1
- quarchpy/connection_specific/connection_mDNS.py.bak +0 -48
- quarchpy/debug/SystemTest.py.bak +0 -188
- quarchpy/debug/simple_terminal.py.bak +0 -50
- quarchpy/fio/FIO_interface.py.bak +0 -322
- quarchpy/qis/qisFuncs.py.bak +0 -265
- quarchpy/run.py.bak +0 -283
- {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/WHEEL +0 -0
- {quarchpy-2.1.20.dev2.dist-info → quarchpy-2.1.20.dev3.dist-info}/top_level.txt +0 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from quarchpy.device.scanDevices import scanDevices, lookupDevice
|
2
|
+
import socket
|
3
|
+
from quarchpy._version import __version__ as quarchpyVersion
|
4
|
+
|
5
|
+
print("Testing with quarchpy version v"+str(quarchpyVersion))
|
6
|
+
|
7
|
+
myScan=scanDevices(target_conn="TCP",ipAddressLookup="192.168.1.167")
|
8
|
+
print("Scan with IP lookup: "+ str(myScan))
|
9
|
+
|
10
|
+
# myScan=scanDevices(target_conn="TCP")
|
11
|
+
# print("Scan with NO IP lookup: "+ str(myScan))
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,504 @@
|
|
1
|
+
import time, sys, os ,logging
|
2
|
+
|
3
|
+
from quarchpy.connection import QISConnection, PYConnection, QPSConnection
|
4
|
+
from quarchpy import user_interface
|
5
|
+
import re
|
6
|
+
|
7
|
+
# Check Python version
|
8
|
+
if sys.version_info.major == 2:
|
9
|
+
# Python 2: Use socket.timeout
|
10
|
+
try:
|
11
|
+
import socket
|
12
|
+
timeout_exception = socket.timeout
|
13
|
+
except AttributeError:
|
14
|
+
timeout_exception = None
|
15
|
+
print("Socket timeout is not available in this Python version.")
|
16
|
+
else:
|
17
|
+
# Python 3: Use built-in TimeoutError
|
18
|
+
timeout_exception = TimeoutError
|
19
|
+
|
20
|
+
class quarchDevice:
|
21
|
+
"""
|
22
|
+
Allows control over a Quarch device, over a wide range of underlying connection methods. This is the core class
|
23
|
+
used for control of all Quarch products.
|
24
|
+
|
25
|
+
"""
|
26
|
+
|
27
|
+
def __init__(self, ConString, ConType="PY", timeout="5"):
|
28
|
+
"""
|
29
|
+
Constructor for quarchDevice, allowing the connection method of the device to be specified.
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
ConString : str
|
34
|
+
|
35
|
+
Connection string, specifying the underlying connection type and module identifier. The underlying
|
36
|
+
connection must be supported both by the connection type and the target module.
|
37
|
+
|
38
|
+
Example:
|
39
|
+
USB:QTL1743 - USB connection with given part number
|
40
|
+
USB:QTL1743-03-015 - USB connection with fully qualified serial number
|
41
|
+
SERIAL:COM4 - Serial connection with COM port (ttyS0 for linux)
|
42
|
+
TCP:192.168.1.55 - LAN(TCP) connection to IP address
|
43
|
+
TELNET:QTL1079-03-004 - LAN(TELNET) connection to netBIOS name (must resolve to IP address)
|
44
|
+
REST:192.168.1.60 - LAN(REST) connection to IP address
|
45
|
+
|
46
|
+
ConType : {'PY', 'QIS', 'QPS'}
|
47
|
+
|
48
|
+
Specifies the software type which runs the connection:
|
49
|
+
PY - (Default) Connection is run via pure Python code
|
50
|
+
|
51
|
+
QIS - Power modules only, connection run via QIS (Quarch Instrument Server) for easy power capture in raw formats.
|
52
|
+
Serial is not supported. IP and port can be specified to connect to a QIS instance running at another location "QIS:192.168.1.100:9722"
|
53
|
+
|
54
|
+
QPS - Power modules only, connection run via QPS (Quarch Power Studio) for automated power capture and analysis within thr QPS graphical environment.
|
55
|
+
Serial is not supported. IP and port can be specified to connect to a QPS instance running at another location "QPS:192.168.1.100:9822"
|
56
|
+
|
57
|
+
timeout : str, optional
|
58
|
+
|
59
|
+
Timeout in seconds for the device to respond.
|
60
|
+
|
61
|
+
"""
|
62
|
+
|
63
|
+
self.ConString = ConString
|
64
|
+
if "serial" not in ConString.lower():
|
65
|
+
self.ConString = ConString.lower()
|
66
|
+
self.ConType = ConType
|
67
|
+
|
68
|
+
try:
|
69
|
+
self.timeout = int(timeout)
|
70
|
+
except:
|
71
|
+
raise Exception("Invalid value for timeout, must be a numeric value")
|
72
|
+
|
73
|
+
if checkModuleFormat(self.ConString) == False:
|
74
|
+
raise Exception("Module format is invalid!")
|
75
|
+
|
76
|
+
# Initializes the object as a python or QIS connection
|
77
|
+
## Python
|
78
|
+
if self.ConType.upper() == "PY":
|
79
|
+
|
80
|
+
# replacing colons
|
81
|
+
numb_colons = self.ConString.count(":")
|
82
|
+
if numb_colons == 2:
|
83
|
+
self.ConString = self.ConString.replace('::', ':')
|
84
|
+
|
85
|
+
if self.ConString.lower().find("qtl") != -1 and self.ConString.lower().find("usb") ==-1:
|
86
|
+
from .scanDevices import get_connection_target
|
87
|
+
self.ConString = get_connection_target(self.ConString)
|
88
|
+
|
89
|
+
# Create the connection object
|
90
|
+
self.connectionObj = PYConnection(self.ConString)
|
91
|
+
self.ConCommsType = self.connectionObj.ConnTypeStr
|
92
|
+
|
93
|
+
# Exposes the connection type and module for later use.
|
94
|
+
self.connectionName = self.connectionObj.ConnTarget
|
95
|
+
self.connectionTypeName = self.connectionObj.ConnTypeStr
|
96
|
+
|
97
|
+
time.sleep(0.1)
|
98
|
+
item = None
|
99
|
+
item = self.connectionObj.connection.sendCommand("*tst?")
|
100
|
+
if "OK" in item:
|
101
|
+
pass
|
102
|
+
elif "FAIL" in item:
|
103
|
+
pass
|
104
|
+
elif item is not None:
|
105
|
+
pass
|
106
|
+
else:
|
107
|
+
raise Exception("No module responded to *tst? command!")
|
108
|
+
time.sleep(0.1)
|
109
|
+
|
110
|
+
## QIS
|
111
|
+
# ConType may be QIS only or QIS:ip:port [:3] checks if the first 3 letters are QIS.
|
112
|
+
elif self.ConType[:3].upper() == "QIS":
|
113
|
+
# If host and port are specified.
|
114
|
+
try:
|
115
|
+
# Extract QIS, host and port.
|
116
|
+
QIS, host, port = self.ConType.split(':')
|
117
|
+
# QIS port should be an int.
|
118
|
+
port = int(port)
|
119
|
+
# If host and port are not specified.
|
120
|
+
except:
|
121
|
+
host = '127.0.0.1'
|
122
|
+
port = 9722
|
123
|
+
|
124
|
+
numb_colons = self.ConString.count(":")
|
125
|
+
if numb_colons == 1:
|
126
|
+
self.ConString = self.ConString.replace(':', '::')
|
127
|
+
|
128
|
+
# Creates the connection object.
|
129
|
+
self.connectionObj = QISConnection(self.ConString, host, port)
|
130
|
+
|
131
|
+
list = self.connectionObj.qis.getDeviceList()
|
132
|
+
list_str = "".join(list).lower()
|
133
|
+
|
134
|
+
timeout = time.time() + int(timeout) # now + n seconds
|
135
|
+
|
136
|
+
# check for device in list, has a timeout
|
137
|
+
while time.time() < timeout:
|
138
|
+
|
139
|
+
# Check if it's a module's QTL number
|
140
|
+
if "qtl" not in self.ConString.lower():
|
141
|
+
|
142
|
+
# If not, check if it contains a valid IP address format
|
143
|
+
ip_address = re.search(r"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}", self.ConString)
|
144
|
+
if not ip_address:
|
145
|
+
raise ValueError(f"ConString {self.ConString} does not contain a valid QTL number or IP address")
|
146
|
+
|
147
|
+
# Attempt to get QTL number from qis "$list details"
|
148
|
+
temp_str = _check_ip_in_qis_list(ip_address.group(), self.connectionObj.qis.get_list_details())
|
149
|
+
if temp_str:
|
150
|
+
# If found
|
151
|
+
self.ConString = temp_str
|
152
|
+
break
|
153
|
+
|
154
|
+
logging.debug("Did not find ip address in list details, attempt targetted qis scan")
|
155
|
+
|
156
|
+
# If it's not present in the list already, then try scanning for it via qis
|
157
|
+
# Scan is purposefully after initial check! 09/03/2023
|
158
|
+
# Valid response example "Located device: 192.168.1.3"
|
159
|
+
if "located" in str(self.connectionObj.qis.scanIP(self.ConString)).lower():
|
160
|
+
# Note - Qis takes a moment or 2 to add this newly located device to the $list 21/03/23
|
161
|
+
timeout += 20 # Extend the timeout as the drive was located
|
162
|
+
|
163
|
+
while time.time() < timeout:
|
164
|
+
# try find the new device again from ipaddress
|
165
|
+
temp_str = _check_ip_in_qis_list(ip_address.group(), self.connectionObj.qis.get_list_details())
|
166
|
+
if temp_str:
|
167
|
+
# If the item is found, break out of this loop
|
168
|
+
self.ConString = temp_str
|
169
|
+
break
|
170
|
+
time.sleep(1) # Slow down the poll
|
171
|
+
else:
|
172
|
+
# if it's not found, continue and allow program to timeout
|
173
|
+
continue
|
174
|
+
# Break out of both loops
|
175
|
+
break
|
176
|
+
|
177
|
+
elif str(self.ConString).lower() in str(list_str).lower():
|
178
|
+
# If we have QTL device, and it's in list, nothing more needs done.
|
179
|
+
break
|
180
|
+
else:
|
181
|
+
time.sleep(1)
|
182
|
+
list = self.connectionObj.qis.getDeviceList()
|
183
|
+
list_str = "".join(list).lower()
|
184
|
+
else:
|
185
|
+
# If we didn't hit a 'break' condition in the above loop, then it timed out
|
186
|
+
raise TimeoutError(f"Could not find module '{self.ConString}' from Qis within specified time")
|
187
|
+
|
188
|
+
self.connectionObj.qis.sendAndReceiveCmd(cmd="$default " + self.ConString)
|
189
|
+
|
190
|
+
## QPS
|
191
|
+
elif self.ConType[:3].upper() == "QPS":
|
192
|
+
try:
|
193
|
+
# Extract QIS, host and port.
|
194
|
+
QIS, host, port = self.ConType.split(':')
|
195
|
+
# QIS port should be an int.
|
196
|
+
port = int(port)
|
197
|
+
# If host and port are not specified.
|
198
|
+
except:
|
199
|
+
host = '127.0.0.1'
|
200
|
+
port = 9822
|
201
|
+
|
202
|
+
numb_colons = self.ConString.count(":")
|
203
|
+
if numb_colons == 1:
|
204
|
+
self.ConString = self.ConString.replace(':', '::')
|
205
|
+
|
206
|
+
self.connectionObj = QPSConnection(host, port)
|
207
|
+
|
208
|
+
## Neither PY or QIS, connection cannot be created.
|
209
|
+
else:
|
210
|
+
raise ValueError("Invalid connection type. Acceptable values [PY,QIS,QPS]")
|
211
|
+
|
212
|
+
logging.debug(os.path.basename(__file__) + " ConString : " + str(self.ConString) + " ConType : " + str(self.ConType))
|
213
|
+
|
214
|
+
|
215
|
+
# def setCanStream(self):
|
216
|
+
# ask module name if = name in list
|
217
|
+
# TODO: expectedResponse does nothing can it be removed
|
218
|
+
# TODO: The connectionObj should be an instance of a common base class such that the IF block here is not needed
|
219
|
+
def sendCommand(self, CommandString, expectedResponse = True):
|
220
|
+
"""
|
221
|
+
Executes a text based command on the device. This is the primary way of controlling a device. The full command set available to use
|
222
|
+
is found in the technical manual for the device.
|
223
|
+
|
224
|
+
Parameters
|
225
|
+
----------
|
226
|
+
CommandString : str
|
227
|
+
|
228
|
+
The text based command string to send to the device
|
229
|
+
|
230
|
+
Returns
|
231
|
+
-------
|
232
|
+
command_response : str or None
|
233
|
+
|
234
|
+
The response text from the module. Multiline responses will be seperated with LF. Some commands
|
235
|
+
do not return a response and None will be returned
|
236
|
+
|
237
|
+
"""
|
238
|
+
|
239
|
+
# send command to log
|
240
|
+
logging.debug(os.path.basename(__file__) + ": "+self.ConType[:3]+" sending command: " + CommandString)
|
241
|
+
|
242
|
+
if self.ConType[:3] == "QIS":
|
243
|
+
|
244
|
+
numb_colons = self.ConString.count(":")
|
245
|
+
if numb_colons == 1:
|
246
|
+
self.ConString = self.ConString.replace(':', '::')
|
247
|
+
|
248
|
+
response = self.connectionObj.qis.sendCmd(self.ConString, CommandString)
|
249
|
+
# send response to log
|
250
|
+
logging.debug(os.path.basename(__file__) + ": "+self.ConType[:3]+" received: " + response)
|
251
|
+
return response
|
252
|
+
|
253
|
+
elif self.ConType == "PY":
|
254
|
+
response = self.connectionObj.connection.sendCommand(CommandString)
|
255
|
+
# send response to log
|
256
|
+
logging.debug(os.path.basename(__file__) + ": "+self.ConType[:3]+" received: " + response)
|
257
|
+
return response
|
258
|
+
|
259
|
+
elif self.ConType[:3] == "QPS":
|
260
|
+
# checking if the command string passed has a $ as first char
|
261
|
+
if CommandString[0] != '$':
|
262
|
+
CommandString = self.ConString + " " + CommandString
|
263
|
+
|
264
|
+
response = self.connectionObj.qps.sendCmdVerbose(CommandString)
|
265
|
+
# send response to log
|
266
|
+
logging.debug(os.path.basename(__file__) + ": "+self.ConType[:3]+" received: " + response)
|
267
|
+
return response
|
268
|
+
|
269
|
+
# Only works for usb
|
270
|
+
# TODO: Can this be marked '_' for private use only
|
271
|
+
def sendBinaryCommand(self, cmd):
|
272
|
+
self.connectionObj.connection.Connection.SendCommand(cmd)
|
273
|
+
return self.connectionObj.connection.Connection.BulkRead()
|
274
|
+
|
275
|
+
# TODO: Not using class hierarchy based connectionObj, recreation of PYConnection may not release the previous handle in time.
|
276
|
+
# QPS and QIS actions are different despite the underlying connection being the same!
|
277
|
+
def openConnection(self):
|
278
|
+
"""
|
279
|
+
Opens the connection to the module. This will be open by default on creation of quarchDevice but this
|
280
|
+
allows re-opening if required.
|
281
|
+
|
282
|
+
"""
|
283
|
+
|
284
|
+
logging.debug("Attempting to open " + self.ConType[:3] + " connection")
|
285
|
+
|
286
|
+
if self.ConType[:3] == "QIS":
|
287
|
+
self.connectionObj.qis.connect() #todo should have a return val so that failed connections are caught.
|
288
|
+
|
289
|
+
elif self.ConType == "PY":
|
290
|
+
del self.connectionObj
|
291
|
+
self.connectionObj = PYConnection(self.ConString)
|
292
|
+
return self.connectionObj
|
293
|
+
|
294
|
+
elif self.ConType[:3] == "QPS":
|
295
|
+
return self.connectionObj.qps.connect(self.ConString)
|
296
|
+
|
297
|
+
else:
|
298
|
+
raise Exception("Connection type not recognised")
|
299
|
+
|
300
|
+
# TODO: Not using class hierarchy based connectionObj. QPS and QIS actions are different despite the underlying connection being the same!
|
301
|
+
def closeConnection(self):
|
302
|
+
"""
|
303
|
+
Closes the connection to the module, freeing the module for other uses. This should always be called whern you are finished with a device.
|
304
|
+
|
305
|
+
"""
|
306
|
+
|
307
|
+
logging.debug("Attempting to close " + self.ConType[:3] + " connection")
|
308
|
+
|
309
|
+
if self.ConType[:3] == "QIS":
|
310
|
+
#self.connectionObj.qis.disconnect()
|
311
|
+
self.connectionObj.qis.closeConnection(conString=self.ConString)
|
312
|
+
elif self.ConType == "PY":
|
313
|
+
self.connectionObj.connection.close()
|
314
|
+
|
315
|
+
elif self.ConType[:3] == "QPS":
|
316
|
+
self.connectionObj.qps.disconnect(self.ConString)
|
317
|
+
|
318
|
+
return "OK"
|
319
|
+
|
320
|
+
|
321
|
+
# TODO: Not using class hierarchy based connectionObj.
|
322
|
+
def resetDevice(self, timeout=10):
|
323
|
+
"""
|
324
|
+
Issues a power-on-reset command to the device. Attempts to recover the connection to the module after reset.
|
325
|
+
Function halts until the timeout is complete or the module is found
|
326
|
+
|
327
|
+
Parameters
|
328
|
+
----------
|
329
|
+
timeout : int
|
330
|
+
|
331
|
+
Number of seconds to wait for the module to re-enumerate and become available
|
332
|
+
|
333
|
+
Returns
|
334
|
+
-------
|
335
|
+
result : bool
|
336
|
+
|
337
|
+
True if the device was found and reconnected, false if it was not and we timed out
|
338
|
+
|
339
|
+
"""
|
340
|
+
|
341
|
+
# send command to log
|
342
|
+
logging.debug(os.path.basename(__file__) + ": sending command: *rst" )
|
343
|
+
|
344
|
+
if self.ConType[:3] == "QIS":
|
345
|
+
|
346
|
+
numb_colons = self.ConString.count(":")
|
347
|
+
if numb_colons == 1:
|
348
|
+
self.ConString = self.ConString.replace(':', '::')
|
349
|
+
|
350
|
+
retval = self.ConString
|
351
|
+
self.connectionObj.qis.sendCmd(self.ConString, "*rst", expectedResponse = False)
|
352
|
+
logging.debug(os.path.basename(__file__) + ": connecting back to " + retval)
|
353
|
+
|
354
|
+
elif self.ConType == "PY":
|
355
|
+
retval = self.ConString
|
356
|
+
self.connectionObj.connection.sendCommand("*rst" , expectedResponse = False)
|
357
|
+
self.connectionObj.connection.close()
|
358
|
+
logging.debug(os.path.basename(__file__) + ": connecting back to " + retval)
|
359
|
+
#pos fix for making new connectionObj. Works for py connection but more complex for qis & qps
|
360
|
+
#self.connectionObj = PYConnection(self.ConString)
|
361
|
+
|
362
|
+
elif self.ConType[:3] == "QPS":
|
363
|
+
# checking if the command string passed has a $ as first char
|
364
|
+
retval = self.ConString
|
365
|
+
CommandString = self.ConString + " " + "*rst"
|
366
|
+
self.connectionObj.qps.sendCmdVerbose(CommandString, expectedResponse = False)
|
367
|
+
logging.debug(os.path.basename(__file__) + ": connecting back to " + retval)
|
368
|
+
|
369
|
+
#TODO: Idealy we want to call an openConnection() funct to set the connectionObj to the new value not creating a new obj
|
370
|
+
|
371
|
+
temp = None
|
372
|
+
startTime = time.time()
|
373
|
+
time.sleep(0.6) #most devices are visable again after 0.6 seconds.
|
374
|
+
while temp == None:
|
375
|
+
try:
|
376
|
+
#user_interface.printText("Restart time is : " + str(time.time() - startTime) + " timeout is : " + str(timeout))
|
377
|
+
temp = getQuarchDevice(retval)
|
378
|
+
except:
|
379
|
+
time.sleep(0.2) # wait before trying again if not timed out.
|
380
|
+
if (time.time() - startTime) > timeout:
|
381
|
+
logging.critical(os.path.basename(__file__) + ": connection failed to " + retval)
|
382
|
+
return False
|
383
|
+
|
384
|
+
self.connectionObj = temp.connectionObj
|
385
|
+
time.sleep(1) #Must wait before sending a command to device. If done instantly device errors out "device busy"
|
386
|
+
return True
|
387
|
+
|
388
|
+
|
389
|
+
def sendAndVerifyCommand(self, commandString, responseExpected="OK", exception=True):
|
390
|
+
"""
|
391
|
+
Sends a command to the device and verifies the response is as expected. This is a simple
|
392
|
+
wrapper of sendCommand and helps write cleaner code in test scripts.
|
393
|
+
|
394
|
+
Parameters
|
395
|
+
----------
|
396
|
+
commandString : str
|
397
|
+
|
398
|
+
The text command to send to the device
|
399
|
+
|
400
|
+
commandString : str, optional
|
401
|
+
|
402
|
+
The expected text response from the module.
|
403
|
+
|
404
|
+
exception : bool, optional
|
405
|
+
|
406
|
+
If True, an exception is raised on mismatch. If False, we just return False
|
407
|
+
|
408
|
+
Returns
|
409
|
+
-------
|
410
|
+
result : bool
|
411
|
+
|
412
|
+
True if we matched the response, False if we did not
|
413
|
+
|
414
|
+
Raises
|
415
|
+
------
|
416
|
+
ValueError
|
417
|
+
If the response does not match AND the exception parameter is set to True
|
418
|
+
|
419
|
+
"""
|
420
|
+
|
421
|
+
responseStr = self.sendCommand(commandString)
|
422
|
+
if (responseStr != responseExpected):
|
423
|
+
if (exception):
|
424
|
+
raise ValueError("Command Sent: " + commandString + ", Expected response: " + responseExpected + ", Response received: " + responseStr)
|
425
|
+
else:
|
426
|
+
return False
|
427
|
+
else:
|
428
|
+
return True
|
429
|
+
|
430
|
+
def getRuntime(self, command="conf:runtimes?"):
|
431
|
+
'''
|
432
|
+
|
433
|
+
:param command: can be overridden to ask for PAM fixture runtime
|
434
|
+
:return:
|
435
|
+
'''
|
436
|
+
runtime = self.sendCommand(command)
|
437
|
+
if runtime.lower().__contains__("fail"):
|
438
|
+
logging.error("runtime check failed, check FW and FPGA are up to date")
|
439
|
+
# if the response matches [int]s then the result was valid, return digits, (otherwise return None)
|
440
|
+
if runtime.endswith("s"):
|
441
|
+
try :
|
442
|
+
runtime = int(runtime[:-1])
|
443
|
+
return runtime
|
444
|
+
except:
|
445
|
+
logging.error("runtime response not a valid int : " + str(runtime))
|
446
|
+
else:
|
447
|
+
return None
|
448
|
+
|
449
|
+
|
450
|
+
def _check_ip_in_qis_list(ip_address, detailed_device_list):
|
451
|
+
"""
|
452
|
+
Checks if the IP address is in qis device list
|
453
|
+
:param detailed_device_list: list formatted return from qis command "$list details"
|
454
|
+
:return String : return contype and constring for module if it's in list, else None
|
455
|
+
"""
|
456
|
+
# logging.debug(f"List details from Qis : \n{str(''.join(detailed_device_list))}")
|
457
|
+
|
458
|
+
for module in detailed_device_list:
|
459
|
+
# Note for future developers : Restricted this to only TCP modules, not RESt
|
460
|
+
if ip_address in module and "tcp" in module.lower():
|
461
|
+
# '1) REST::QTL2312-01-009 IP:192.168.1.5 Port:80 NBName:2312-01-009 Stream:No Name:Power Analysis Module'
|
462
|
+
# Split on spaces and grab second element ("tcp::qtl2312-01-009")
|
463
|
+
ret_string = module.split()[1]
|
464
|
+
return ret_string
|
465
|
+
|
466
|
+
# If the ip address wasn't found, then return none
|
467
|
+
return None
|
468
|
+
|
469
|
+
# TODO: Can we make this an '_' internal function?
|
470
|
+
def checkModuleFormat(ConString):
|
471
|
+
ConnectionTypes = ["USB", "SERIAL", "TELNET", "REST", "TCP"] # acceptable conTypes
|
472
|
+
|
473
|
+
conTypeSpecified = ConString[:ConString.find(':')]
|
474
|
+
|
475
|
+
correctConType = False
|
476
|
+
for value in ConnectionTypes:
|
477
|
+
if value.lower() == conTypeSpecified.lower():
|
478
|
+
correctConType = True
|
479
|
+
|
480
|
+
if not correctConType:
|
481
|
+
logging.warning("Invalid connection type specified in Module string, use one of [USB|SERIAL|TELNET|REST|TCP]")
|
482
|
+
return False
|
483
|
+
|
484
|
+
numb_colons = ConString.count(":")
|
485
|
+
if numb_colons > 2 or numb_colons <= 0:
|
486
|
+
logging.warning("Invalid number of colons in module string")
|
487
|
+
return False
|
488
|
+
|
489
|
+
return True
|
490
|
+
|
491
|
+
|
492
|
+
def getQuarchDevice(connectionTarget, ConType="PY", timeout="5"):
|
493
|
+
'''creates a quarch device to be returned. Handles sub devices in quarch arrays. '''
|
494
|
+
from .quarchArray import quarchArray
|
495
|
+
if connectionTarget.__contains__("<") and connectionTarget.__contains__(">"):
|
496
|
+
connectionTarget, portNumber = connectionTarget.split("<")
|
497
|
+
portNumber = portNumber[:-1]
|
498
|
+
myDevice = quarchDevice(connectionTarget, ConType="PY", timeout="5")
|
499
|
+
myArrayController = quarchArray(myDevice)
|
500
|
+
mySubDevice = myArrayController.getSubDevice(portNumber)
|
501
|
+
myDevice = mySubDevice
|
502
|
+
else:
|
503
|
+
myDevice = quarchDevice(connectionTarget, ConType=ConType, timeout=timeout)
|
504
|
+
return myDevice
|
@@ -0,0 +1,67 @@
|
|
1
|
+
from .device import quarchDevice
|
2
|
+
import logging
|
3
|
+
from quarchpy.user_interface.user_interface import printText
|
4
|
+
|
5
|
+
class quarchPPM(quarchDevice):
|
6
|
+
def __init__(self, originObj):
|
7
|
+
|
8
|
+
self.connectionObj = originObj.connectionObj
|
9
|
+
self.ConString = originObj.ConString
|
10
|
+
self.ConType = originObj.ConType
|
11
|
+
numb_colons = self.ConString.count(":")
|
12
|
+
if numb_colons == 1:
|
13
|
+
self.ConString = self.ConString.replace(':', '::')
|
14
|
+
|
15
|
+
def startStream(self, fileName='streamData.txt', fileMaxMB=200000, streamName ='Stream With No Name', streamDuration = None, streamAverage = None, releaseOnData = False, separator=",", inMemoryData = False):
|
16
|
+
return self.connectionObj.qis.startStream(self.ConString, fileName, fileMaxMB, streamName, streamAverage, releaseOnData, separator, streamDuration, inMemoryData)
|
17
|
+
|
18
|
+
def streamRunningStatus(self):
|
19
|
+
return self.connectionObj.qis.streamRunningStatus(self.ConString)
|
20
|
+
|
21
|
+
def streamBufferStatus(self):
|
22
|
+
return self.connectionObj.qis.streamBufferStatus(self.ConString)
|
23
|
+
|
24
|
+
def streamInterrupt(self):
|
25
|
+
return self.connectionObj.qis.streamInterrupt()
|
26
|
+
|
27
|
+
def waitStop(self):
|
28
|
+
return self.connectionObj.qis.waitStop()
|
29
|
+
|
30
|
+
def streamResampleMode(self, streamCom):
|
31
|
+
if streamCom.lower() == "off" or streamCom[0:-2].isdigit():
|
32
|
+
retVal = self.connectionObj.qis.sendAndReceiveCmd(cmd="stream mode resample " + streamCom.lower(),
|
33
|
+
device=self.ConString)
|
34
|
+
if "fail" in retVal.lower():
|
35
|
+
logging.error(retVal)
|
36
|
+
else:
|
37
|
+
retVal = "Invalid resampling argument. Valid options are: off, [x]ms or [x]us."
|
38
|
+
logging.error(retVal)
|
39
|
+
return retVal
|
40
|
+
|
41
|
+
def stopStream(self):
|
42
|
+
return self.connectionObj.qis.stopStream(self)
|
43
|
+
|
44
|
+
'''
|
45
|
+
Simple function to check the output mode of the power module, setting it to 3v3 if required
|
46
|
+
then enabling the outputs if not already done. This will result in the module being turned on
|
47
|
+
and supplying power
|
48
|
+
'''
|
49
|
+
def setupPowerOutput(myModule):
|
50
|
+
# Output mode is set automatically on HD modules using an HD fixture, otherwise we will chose 5V mode for this example
|
51
|
+
outModeStr = myModule.sendCommand("config:output Mode?")
|
52
|
+
if "DISABLED" in outModeStr:
|
53
|
+
try:
|
54
|
+
drive_voltage = raw_input(
|
55
|
+
"\n Either using an HD without an intelligent fixture or an XLC.\n \n>>> Please select a voltage [3V3, 5V]: ") or "3V3" or "5V"
|
56
|
+
except NameError:
|
57
|
+
drive_voltage = input(
|
58
|
+
"\n Either using an HD without an intelligent fixture or an XLC.\n \n>>> Please select a voltage [3V3, 5V]: ") or "3V3" or "5V"
|
59
|
+
|
60
|
+
myModule.sendCommand("config:output:mode:" + drive_voltage)
|
61
|
+
|
62
|
+
# Check the state of the module and power up if necessary
|
63
|
+
powerState = myModule.sendCommand("run power?")
|
64
|
+
# If outputs are off
|
65
|
+
if "OFF" in powerState or "PULLED" in powerState: # PULLED comes from PAM
|
66
|
+
# Power Up
|
67
|
+
printText("\n Turning the outputs on:"), myModule.sendCommand("run:power up"), "!"
|