quarchpy 2.1.17.dev2__py2.py3-none-any.whl → 2.1.18.dev1__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.
Files changed (82) hide show
  1. quarchpy/.idea/workspace.xml +41 -41
  2. quarchpy/__pycache__/_version.cpython-311.pyc +0 -0
  3. quarchpy/__pycache__/run.cpython-311.pyc +0 -0
  4. quarchpy/_version.py +1 -1
  5. quarchpy/connection_specific/QPS/qis/help.txt +1 -7
  6. quarchpy/connection_specific/QPS/qis/qis.jar +0 -0
  7. quarchpy/connection_specific/QPS/qis/qis_lib/CInterface-1.7.04.jar +0 -0
  8. quarchpy/connection_specific/QPS/qps.jar +0 -0
  9. quarchpy/connection_specific/QPS/scriptCommands.txt +2 -2
  10. quarchpy/connection_specific/__pycache__/connection_QPS.cpython-311.pyc +0 -0
  11. quarchpy/connection_specific/__pycache__/connection_ReST.cpython-311.pyc +0 -0
  12. quarchpy/connection_specific/connection_mDNS.py +4 -7
  13. quarchpy/connection_specific/connection_mDNS.py.bak +48 -0
  14. quarchpy/debug/SystemTest.py +6 -1
  15. quarchpy/debug/SystemTest.py.bak +188 -0
  16. quarchpy/debug/__pycache__/SystemTest.cpython-311.pyc +0 -0
  17. quarchpy/debug/__pycache__/module_debug.cpython-311.pyc +0 -0
  18. quarchpy/device/__pycache__/scanDevices.cpython-311.pyc +0 -0
  19. quarchpy/device/scanDevices.py +10 -25
  20. quarchpy/device/scanDevices.py.bak +645 -0
  21. quarchpy/docs/CHANGES.rst +14 -0
  22. quarchpy/docs/_build/doctrees/CHANGES.doctree +0 -0
  23. quarchpy/docs/_build/doctrees/environment.pickle +0 -0
  24. quarchpy/docs/_build/doctrees/source/changelog.doctree +0 -0
  25. quarchpy/docs/_build/doctrees/source/quarchpy.fio.doctree +0 -0
  26. quarchpy/docs/_build/doctrees/source/quarchpy.qis.doctree +0 -0
  27. quarchpy/docs/_build/doctrees/source/quarchpy.qps.doctree +0 -0
  28. quarchpy/docs/_build/html/CHANGES.html +121 -101
  29. quarchpy/docs/_build/html/_sources/CHANGES.rst.txt +14 -0
  30. quarchpy/docs/_build/html/genindex.html +27 -2
  31. quarchpy/docs/_build/html/index.html +54 -51
  32. quarchpy/docs/_build/html/objects.inv +0 -0
  33. quarchpy/docs/_build/html/py-modindex.html +5 -0
  34. quarchpy/docs/_build/html/searchindex.js +1 -1
  35. quarchpy/docs/_build/html/source/changelog.html +175 -152
  36. quarchpy/docs/_build/html/source/modules.html +1 -1
  37. quarchpy/docs/_build/html/source/quarchpy.fio.html +28 -2
  38. quarchpy/docs/_build/html/source/quarchpy.html +12 -1
  39. quarchpy/docs/_build/html/source/quarchpy.qis.html +12 -0
  40. quarchpy/docs/_build/html/source/quarchpy.qps.html +14 -2
  41. quarchpy/fio/__pycache__/FIO_interface.cpython-311.pyc +0 -0
  42. quarchpy/qis/__pycache__/qisFuncs.cpython-311.pyc +0 -0
  43. quarchpy/qis/qisFuncs.py +58 -12
  44. quarchpy/qps/__pycache__/qpsFuncs.cpython-311.pyc +0 -0
  45. quarchpy/qps/qpsFuncs.py +61 -20
  46. quarchpy/qps/qpsFuncs.py.bak +66 -18
  47. {quarchpy-2.1.17.dev2.dist-info → quarchpy-2.1.18.dev1.dist-info}/METADATA +18 -1
  48. {quarchpy-2.1.17.dev2.dist-info → quarchpy-2.1.18.dev1.dist-info}/RECORD +50 -79
  49. quarchpy/connection_specific/QPS/qis/qis_lib/CInterface-1.7.02.jar +0 -0
  50. quarchpy/connection_specific/QPS/qis/qis_lib/CInterface-1.7.8.jar +0 -0
  51. quarchpy/connection_specific/QPS/qis/qis_lib/Collections-1.2.jar +0 -0
  52. quarchpy/connection_specific/QPS/qis/qis_lib/Collections-2.4.jar +0 -0
  53. quarchpy/connection_specific/QPS/qis/qis_lib/Desktop-1.0.jar +0 -0
  54. quarchpy/connection_specific/QPS/qis/qis_lib/Desktop-1.1.jar +0 -0
  55. quarchpy/connection_specific/QPS/qis/qis_lib/Executor-3.11.jar +0 -0
  56. quarchpy/connection_specific/QPS/qis/qis_lib/Executor-3.13.jar +0 -0
  57. quarchpy/connection_specific/QPS/qis/qis_lib/JNA-1.0.jar +0 -0
  58. quarchpy/connection_specific/QPS/qis/qis_lib/JNA-1.2.jar +0 -0
  59. quarchpy/connection_specific/QPS/qis/qis_lib/OS-1.6.jar +0 -0
  60. quarchpy/connection_specific/QPS/qis/qis_lib/OS-1.8.jar +0 -0
  61. quarchpy/connection_specific/QPS/qis/qis_lib/QuarchCommon-0.2.9.jar +0 -0
  62. quarchpy/connection_specific/QPS/qis/qis_lib/SystemTray-4.2.1.jar +0 -0
  63. quarchpy/connection_specific/QPS/qis/qis_lib/SystemTray-4.4.jar +0 -0
  64. quarchpy/connection_specific/QPS/qis/qis_lib/Updates-1.1.jar +0 -0
  65. quarchpy/connection_specific/QPS/qis/qis_lib/Utilities-1.39.jar +0 -0
  66. quarchpy/connection_specific/QPS/qis/qis_lib/Utilities-1.46.jar +0 -0
  67. quarchpy/connection_specific/QPS/qis/qis_lib/commons-csv-1.8.jar +0 -0
  68. quarchpy/connection_specific/QPS/qis/qis_lib/javassist-3.29.2-GA.jar +0 -0
  69. quarchpy/connection_specific/QPS/qis/qis_lib/jna-jpms-5.12.1.jar +0 -0
  70. quarchpy/connection_specific/QPS/qis/qis_lib/jna-platform-jpms-5.12.1.jar +0 -0
  71. quarchpy/connection_specific/QPS/qis/qis_lib/kotlin-stdlib-1.7.22.jar +0 -0
  72. quarchpy/connection_specific/QPS/qis/qis_lib/kotlin-stdlib-1.9.21.jar +0 -0
  73. quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-api-2.0.9.jar +0 -0
  74. quarchpy/connection_specific/QPS/qis/qis_lib/slf4j-simple-2.0.9.jar +0 -0
  75. quarchpy/connection_specific/QPS/qis/resources/filters/filters.csv +0 -1004
  76. quarchpy/connection_specific/QPS/qis/resources/filters/iec_filters.xml +0 -21
  77. quarchpy/connection_specific/QPS/qps_lib/QuarchCommon-0.2.11.jar +0 -0
  78. quarchpy/connection_specific/QPS/qps_lib/commons-lang3-3.12.0.jar +0 -0
  79. quarchpy/connection_specific/QPS/qps_lib/opencsv-5.9.jar +0 -0
  80. quarchpy/connection_specific/QPS/qps_lib/qis-1.40.jar +0 -0
  81. {quarchpy-2.1.17.dev2.dist-info → quarchpy-2.1.18.dev1.dist-info}/WHEEL +0 -0
  82. {quarchpy-2.1.17.dev2.dist-info → quarchpy-2.1.18.dev1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,645 @@
1
+ import time
2
+ import socket
3
+ import sys
4
+ import operator
5
+ import logging
6
+ import os
7
+
8
+ from sys import platform
9
+
10
+ from quarchpy.config_files.quarch_config_parser import return_module_type_list
11
+ from quarchpy.user_interface import*
12
+ from quarchpy.user_interface import User_interface
13
+ try:
14
+ from quarchpy.connection_specific.connection_USB import importUSB # , USBConn
15
+ except:
16
+ printText("System Compatibility issue - Is your Python architecture consistent with the Operating System?")
17
+ pass
18
+ from quarchpy.device import quarchDevice, quarchArray
19
+ from quarchpy.connection_specific.connection_Serial import serialList, serial
20
+ from quarchpy.device.quarchArray import isThisAnArrayController
21
+ from quarchpy.connection_specific.connection_USB import TQuarchUSB_IF
22
+ from quarchpy.connection_specific import connection_ReST
23
+ from quarchpy.connection_specific.connection_mDNS import MyListener
24
+ from quarchpy.utilities import TestCenter
25
+
26
+
27
+ '''
28
+ Merge two dictionaries and return the result
29
+ '''
30
+ def mergeDict(x, y):
31
+ if (y is None):
32
+ return x
33
+ else:
34
+ merged = x.copy()
35
+ merged.update(y)
36
+ return merged
37
+
38
+
39
+ '''
40
+ Scan for Quarch modules across all available COM ports
41
+ '''
42
+ def list_serial(debuPrint=False):
43
+ serial_ports = serialList.comports()
44
+ serial_modules = dict()
45
+
46
+ for i in serial_ports:
47
+ logging.debug("Scanning for Quarch devices on: " + str(i))
48
+ try:
49
+ ser = serial.Serial(i[0], 19200, timeout=0.5)
50
+ ser.write(b'*serial?\r\n')
51
+ s = ser.read(size=64)
52
+ serial_module = s.splitlines()[1]
53
+
54
+ serial_module = str(serial_module).replace("'", "").replace("b", "")
55
+
56
+ if "QTL" not in serial_module:
57
+ serial_module = "QTL" + serial_module
58
+
59
+ module = str(i[0]), str(serial_module)
60
+
61
+ if serial_module[7] == "-" and serial_module[10] == "-":
62
+ serial_modules["SERIAL:" + str(i[0])] = serial_module
63
+ logging.debug("Located quarch module: " + serial_module)
64
+
65
+ ser.close()
66
+ logging.debug("Finished scanning for Quarch devices on: " + str(i))
67
+ except Exception as err:
68
+ logging.debug("Exception during serial scan: " + str(err))
69
+ pass
70
+ return serial_modules
71
+
72
+
73
+ '''
74
+ Scan for all Quarch devices available over USB
75
+ '''
76
+ def list_USB(debuPrint=False):
77
+ QUARCH_VENDOR_ID = 0x16d0
78
+ QUARCH_PRODUCT_ID1 = 0x0449
79
+
80
+ usb1 = importUSB()
81
+
82
+ context = usb1.USBContext()
83
+ usb_list = context.getDeviceList()
84
+
85
+ if (debuPrint): printText(usb_list)
86
+
87
+ usb_modules = dict()
88
+ hdList = []
89
+
90
+ usb_permission_error = False
91
+
92
+ for i in usb_list:
93
+ if hex(i.device_descriptor.idVendor) == hex(QUARCH_VENDOR_ID) and hex(i.device_descriptor.idProduct) == hex(
94
+ QUARCH_PRODUCT_ID1):
95
+ try:
96
+ logging.debug("Opening USB handle to quarch module: " + str(i))
97
+ i_handle = i.open()
98
+ except Exception as err:
99
+ logging.debug("USB port open exception: " + str(err))
100
+ if "LIBUSB_ERROR_ACCESS [-3]" in str(err):
101
+ logging.debug("Unable to communicate with Quarch module over USB, device may be in use already.")
102
+ if not platform == "win32":
103
+ if not os.path.isfile("/etc/udev/rules.d/20-quarchmodules.rules"):
104
+ usb_permission_error = True
105
+ usb_modules["USB:???"] = "LOCKED MODULE"
106
+
107
+
108
+ try:
109
+ module_sn = i_handle.getASCIIStringDescriptor(3)
110
+ if "1944" in module_sn or "2098" in module_sn : #use enclosure number instead of serial number
111
+ hdList.append(i)
112
+ except Exception as err:
113
+ logging.debug("USB exception on reading serial number: " + str(err))
114
+ usb_modules["USB:???"] = "LOCKED MODULE"
115
+ continue
116
+
117
+ try:
118
+ if (debuPrint): printText(i_handle.getASCIIStringDescriptor(3) + " " + i_handle.getASCIIStringDescriptor(
119
+ 2) + " " + i_handle.getASCIIStringDescriptor(1))
120
+ except Exception as err:
121
+ logging.error("USB exception on reading descriptor strings: " + str(err))
122
+ usb_modules["USB:???"] = "LOCKED MODULE"
123
+ continue
124
+
125
+ if "QTL" not in module_sn:
126
+ module_sn = "QTL" + module_sn.strip()
127
+ else:
128
+ module_sn = module_sn.strip()
129
+
130
+ if (debuPrint): printText(module_sn)
131
+
132
+ usb_modules["USB:" + module_sn] = module_sn
133
+ logging.debug("Located USB module: " + module_sn)
134
+
135
+ try:
136
+ logging.debug("Closing USB handle to quarch module: " + str(i))
137
+ i_handle.close()
138
+ except Exception as err:
139
+ logging.error("Exception on closing USB port: " + str(err))
140
+ continue
141
+
142
+ # before returning the list of usb modules scan through the list for a 1944 create a quarch device and use sendCommand("*enclosure?")
143
+
144
+ for module in hdList:
145
+
146
+ QquarchDevice = None
147
+ quarchDevice = None
148
+ quarchDevice = module
149
+ QquarchDevice = TQuarchUSB_IF(context)
150
+ QquarchDevice.connection = quarchDevice
151
+ QquarchDevice.OpenPort()
152
+ time.sleep(0.02) # sleep sometimes needed before sending comand directly after opening device
153
+ QquarchDevice.SetTimeout(2000)
154
+ serialNo = (QquarchDevice.RunCommand("*serial?")).replace("\r\n", "")
155
+ enclNo = (QquarchDevice.RunCommand("*enclosure?")).replace("\r\n", "")
156
+
157
+ keyToFind = "USB:QTL" + serialNo
158
+
159
+ if keyToFind in usb_modules:
160
+ del usb_modules[keyToFind]
161
+ usb_modules["USB:QTL" + enclNo] = "QTL" + enclNo
162
+ logging.debug("Located USB module: QTL" + enclNo)
163
+
164
+ QquarchDevice.ClosePort()
165
+ QquarchDevice.deviceHandle = None
166
+
167
+
168
+ if usb_permission_error:
169
+ logging.warning("Potential permission error accessing Quarch module(s) via USB.")
170
+ logging.warning("If unknown, run the command 'sudo python3 -m quarchpy.run debug --fixusb' to add a new usb rule.")
171
+
172
+ return usb_modules
173
+
174
+
175
+ '''
176
+ List all Quarch devices found over LAN, using a UDP broadcast scan
177
+ '''
178
+ def list_network(target_conn="all", debugPring=False, lanTimeout=1, ipAddressLookup=None):
179
+
180
+ retVal={}
181
+
182
+ lan_modules = dict()
183
+
184
+ specifiedDevice = None
185
+
186
+ if ipAddressLookup is not None:
187
+ # Attempts to find the device through UDP then REST
188
+ specifiedDevice = lookupDevice(str(ipAddressLookup).strip(), mySocket, lan_modules )
189
+
190
+ # Broadcast the message.
191
+ logging.debug("Broadcast LAN discovery message for UDP scan to all network interfaces")
192
+ ipList = socket.gethostbyname_ex(socket.gethostname())
193
+ logging.debug(os.path.basename(__file__) + ": Discovered the following interfaces: " + str(ipList))
194
+
195
+ for ip in ipList[2]:
196
+
197
+ logging.debug(os.path.basename(__file__) + ": Broadcasting on : " + ip)
198
+
199
+ try:
200
+
201
+ mySocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
202
+ mySocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
203
+ mySocket.settimeout(lanTimeout)
204
+ mySocket.bind((ip,56732))
205
+
206
+ except Exception as err:
207
+
208
+ logging.debug("Error while trying to bind to network interfaces: "+" Error: "+str(err))
209
+
210
+
211
+
212
+ mySocket.sendto(b'Discovery: Who is out there?\0\n', ('255.255.255.255', 30303))
213
+
214
+ counter = 0
215
+
216
+ # Receive messages until timeout.
217
+ while True:
218
+ network_modules = {}
219
+ counter += 1
220
+ # Receive raw message until timeout, then break.
221
+ try:
222
+ msg_received = mySocket.recvfrom(256)
223
+ except:
224
+ # check if any a device was targeted directly and allow parse
225
+ if specifiedDevice is not None:
226
+ msg_received = specifiedDevice
227
+ specifiedDevice = None
228
+ else:
229
+ break
230
+ cont = 0
231
+
232
+ # print(msg_received)
233
+ # Used split \r\n since values of 13 or 10 were looked at as /r and /n when using splitlines
234
+ # This fixes for all cases except if 13 is followed by 10.
235
+ splits = msg_received[0].split(b"\r\n")
236
+ del splits[-1]
237
+ for lines in splits:
238
+ if cont <= 1:
239
+ index = cont
240
+ data = repr(lines).replace("'", "").replace("b", "")
241
+ cont += 1
242
+ else:
243
+ index = repr(lines[0]).replace("'", "")
244
+ data = repr(lines[1:]).replace("'", "").replace("b", "")
245
+
246
+ network_modules[index] = data
247
+
248
+ module_name = get_user_level_serial_number(network_modules)
249
+ logging.debug("Found UDP response: " + module_name)
250
+
251
+ ip_module = msg_received[1][0].strip()
252
+
253
+ try:
254
+ # Add a QTL before modules without it.
255
+ if "QTL" not in module_name.decode("utf-8"):
256
+ module_name = "QTL" + module_name.decode("utf-8")
257
+ except:
258
+ # Add a QTL before modules without it.
259
+ if "QTL" not in module_name:
260
+ module_name = "QTL" + module_name
261
+
262
+ # Checks if there's a value in the TELNET key.
263
+ if (target_conn.lower() == "all" or target_conn.lower() == "telnet"):
264
+ if network_modules.get("\\x8a") or network_modules.get("138"):
265
+ # Append the information to the list.
266
+ lan_modules["TELNET:" + ip_module] = module_name
267
+ logging.debug("Found Telnet module: " + module_name)
268
+
269
+ # Checks if there's a value in the REST key.
270
+ if (target_conn.lower() == "all" or target_conn.lower() == "rest"):
271
+ if network_modules.get("\\x84") or network_modules.get("132"):
272
+ # Append the information to the list.
273
+ lan_modules["REST:" + ip_module] = module_name
274
+ logging.debug("Found REST module: " + module_name)
275
+
276
+ # Checks if there's a value in the TCP key.
277
+ if (target_conn.lower() == "all" or target_conn.lower() == "tcp"):
278
+ if network_modules.get("\\x85") or network_modules.get("133"):
279
+ # Append the information to the list.
280
+ lan_modules["TCP:" + ip_module] = module_name
281
+ logging.debug("Found TCP module: " + module_name)
282
+
283
+ mySocket.close()
284
+ logging.debug("Finished UDP scan")
285
+ retVal.update(lan_modules)
286
+ return retVal
287
+
288
+
289
+ ''''''
290
+ def get_user_level_serial_number(network_modules):
291
+ list_of_multi_module_units = ["1995"] # List of modules that require enclosure number + Port to be displayed.
292
+
293
+ # Filter the raw message to get the module and ip address.
294
+ if "134" in network_modules.keys():
295
+ module_name = network_modules.get("134").strip() # enclosure number only
296
+ for module in list_of_multi_module_units:
297
+ if module in module_name:
298
+ module_name += "-" + network_modules.get("135").strip() # enclosure number with port
299
+ break
300
+ elif "\\x86" in network_modules.keys():
301
+ module_name = network_modules.get("\\x86").strip() # enclosure number only
302
+ for module in list_of_multi_module_units:
303
+ if module in module_name:
304
+ module_name += "-" + network_modules.get("\\x87").strip() # enclosure number with port
305
+ break
306
+ else:
307
+ if "131" in network_modules.keys():
308
+ module_name = module_name = network_modules.get("131").strip() # serial number
309
+ elif "\\x83" in network_modules.keys():
310
+ module_name = module_name = network_modules.get("\\x83").strip() # serial number
311
+
312
+ return module_name
313
+
314
+
315
+ ''''''
316
+ def lookupDevice(ipAddressLookup, mySocket, lan_modules):
317
+ try:
318
+ printText("Ipaddress lookup " + ipAddressLookup)
319
+ # For future reference, 0 is the C terminator for a string
320
+ mySocket.sendto(b'Discovery: Who is out there?\0\n', (str(ipAddressLookup).strip(), 30303))
321
+ specifiedDevice = mySocket.recvfrom(256)
322
+ # Check to see if the response contains the connection protocol
323
+ if ("\\x8a") or ("138") or ("\\x84") or ("132") or ("\\x85") or ("133") not in specifiedDevice:
324
+ # If not allow it to fall-back to REST
325
+ specifiedDevice = None
326
+ else:
327
+ # Exit as device was found correctly
328
+ return specifiedDevice
329
+ except Exception as e:
330
+ printText("Error during UDP lookup " + str(e))
331
+ printText("Is the IP address correct?\r\n")
332
+ # Return if there's an error
333
+ return None
334
+
335
+ if specifiedDevice is None:
336
+ try:
337
+ restCon = connection_ReST.ReSTConn(str(ipAddressLookup).replace("\r\n", ""))
338
+ restDevice = restCon.sendCommand("*serial?")
339
+ if not str(restDevice).startswith("QTL"):
340
+ restDevice = "QTL" + restDevice
341
+ # Add the item to list
342
+ lan_modules["REST:" + str(ipAddressLookup).replace("\r\n", "")] = restDevice
343
+
344
+ except Exception as e:
345
+ printText("Error During REST scan " + str(e))
346
+
347
+ # Needs to return None so previous method will not attempt another lookup.
348
+ return None
349
+
350
+
351
+ """
352
+ Takes in the connection target and returns the serial number of a module found on the standard scan.
353
+
354
+ Parameters
355
+ ----------
356
+ connectionTarget= : str
357
+ The connection target of the module you would like to know the serial number of.
358
+
359
+ Returns
360
+ -------
361
+ ret_val : str
362
+ The Serial number of the supplied device.
363
+
364
+ """
365
+ def getSerialNumberFromConnectionTarget(connectionTarget):
366
+ myDict = scanDevices(favouriteOnly=False)
367
+ for k,v in myDict.items():
368
+ if k == connectionTarget:
369
+ return v
370
+ return None
371
+
372
+
373
+ """
374
+ Takes in the connection type and serial number of a module and returns the connection target.
375
+
376
+ Parameters
377
+ ----------
378
+ module_string= : str
379
+ The connection type and serial number combination eg. TCP:QTL1999-05-005.
380
+
381
+ scan_dictionary= :dict, optional
382
+ A scan dictionary can be passed so that a scan does not need to take place on every call.
383
+ This would be advised if calling this for every item in a list of serial numbers.
384
+
385
+ connection_preference= : list str, optional
386
+ The preference of which connection type to prioratise if none it given.
387
+ Defaults to "USB", "TCP", "SERIAL", "REST", "TELNET" in that order.
388
+
389
+ include_conn_type = : boolean, optional
390
+ Decided whether the connection type will appear in the return value eg. TCP:192.168.1.1 vs 192.168.1.1
391
+
392
+ Returns
393
+ -------
394
+ ret_val : str
395
+ The Connection target of the supplied device.
396
+
397
+ """
398
+ def get_connection_target(module_string ,scan_dictionary=None, connection_preference= None, include_conn_type = True):
399
+ logging.debug("Getting connection target for : "+ str(module_string))
400
+ if connection_preference == None:
401
+ connection_preference = ["USB", "TCP", "SERIAL", "REST", "TELNET"]
402
+ module_string.replace("::", ":") #QIS/QPS format to QuarchPy format
403
+ delimeter_pos = module_string.find(":")
404
+ if delimeter_pos == -1:
405
+ con_type = None
406
+ serial_number = module_string.lower()
407
+ else:
408
+ con_type = module_string[:delimeter_pos]
409
+ serial_number = module_string[delimeter_pos + 1:].lower()
410
+ if serial_number.find("qtl") !=-1:
411
+ serial_number=serial_number.replace("qtl","")
412
+ if scan_dictionary is None:
413
+ logging.debug("Scanning for devices...")
414
+ scan_dictionary = scanDevices(favouriteOnly=False,filterStr=[serial_number])
415
+
416
+ ret_val="Fail Module Not Found"
417
+
418
+ if con_type is None:
419
+ connection_found = False
420
+ for con_type in connection_preference:
421
+ if connection_found is False:
422
+ for k, v in scan_dictionary.items():
423
+ if k.__contains__(con_type):
424
+ ret_val = k
425
+ connection_found = True
426
+ else:
427
+ for k, v in scan_dictionary.items():
428
+ if k.lower().__contains__(con_type.lower()):
429
+ ret_val=k
430
+
431
+ if not include_conn_type and not ret_val.__contains__("Fail"):
432
+ delimeter_pos = ret_val.find(":")
433
+ ret_val = ret_val[delimeter_pos + 1:]
434
+
435
+ return ret_val
436
+
437
+
438
+ '''
439
+ Scans for Quarch modules across the given interface(s). Returns a dictionary of module addresses and serial numbers
440
+ '''
441
+ def filter_module_type(module_type_filter, found_devices):
442
+ """
443
+ Used in scandevices to filter modules by their type.
444
+ Uses config files.
445
+
446
+ :param module_type_filter: Acceptable values are 'Cable', 'Card', 'Drive', 'Power', 'Switch'
447
+ :param found_devices: List of found devices passed from scan_devices
448
+ :return: Returns all devices in found devices that are of 'module filter type'
449
+ """
450
+ accepted_qtl_numbers = return_module_type_list(module_type_filter)
451
+ accepted_qtl_numbers = [x.lower() for x in accepted_qtl_numbers]
452
+ filtered_devices = {}
453
+ if not accepted_qtl_numbers:
454
+ return {}
455
+ for key, value in found_devices.items():
456
+ if "qtl" in str(value).lower():
457
+ qtl_num = str(value[str(value.lower()).index("qtl"):str(value).index("-")]).lower()
458
+ if any(qtl_num in x for x in accepted_qtl_numbers):
459
+ filtered_devices.update({key: value})
460
+ return filtered_devices
461
+
462
+ def scan_mDNS(mdnsListener):
463
+ from zeroconf import ServiceBrowser, Zeroconf
464
+ zeroconf = Zeroconf()
465
+ listener = mdnsListener
466
+ browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener)
467
+
468
+
469
+ '''
470
+ Scans for Quarch modules across the given interface(s). Returns a dictionary of module addresses and serial numbers
471
+ '''
472
+ def scanDevices(target_conn="all", lanTimeout=1, scanInArray=True, favouriteOnly=True,filterStr=None,
473
+ module_type_filter=None, ipAddressLookup=None):
474
+ foundDevices = dict()
475
+ scannedArrays = list()
476
+
477
+
478
+ if target_conn.lower() == "all":
479
+ foundDevices = list_USB()
480
+ foundDevices = mergeDict(foundDevices, list_serial())
481
+ try:
482
+ #This will fail if the test machine is not connected to a network
483
+ foundDevices = mergeDict(foundDevices, list_network("all", ipAddressLookup=ipAddressLookup, lanTimeout=lanTimeout))
484
+ try:
485
+ mdnsListener = MyListener()
486
+ scan_mDNS(mdnsListener)
487
+ foundDevices = mergeDict(foundDevices, mdnsListener.found_devices)
488
+ except Exception as mdnsExcept:
489
+ logging.debug("An error occurred while trying to use the mdns listner to scan\n" +mdnsExcept)
490
+ except Exception as e:
491
+ logging.error(e)
492
+ logging.warning("Network scan failed, check network connection")
493
+ # print(foundDevices)
494
+
495
+ if target_conn.lower() == "serial":
496
+ foundDevices = list_serial()
497
+
498
+ if target_conn.lower() == "usb":
499
+ foundDevices = list_USB()
500
+
501
+ if target_conn.lower() == "tcp" or target_conn.lower() == "rest" or target_conn.lower() == "telnet":
502
+ foundDevices = list_network(target_conn, ipAddressLookup=ipAddressLookup, lanTimeout=lanTimeout)
503
+
504
+ if (scanInArray):
505
+ for k, v in foundDevices.items(): # k=Connection target, v=serial number
506
+ if (k not in scannedArrays):
507
+ scannedArrays.append(k)
508
+ if (isThisAnArrayController(v)):
509
+ try:
510
+ myQuarchDevice = quarchDevice(k)
511
+ myArrayControler = quarchArray(myQuarchDevice)
512
+ scanDevices = myArrayControler.scanSubModules()
513
+ foundDevices = mergeDict(foundDevices, scanDevices)
514
+ myArrayControler.closeConnection()
515
+ except Exception as e:
516
+ logging.debug(e, exc_info=True)
517
+ logging.debug("Cannot get serial number. Quarch device may be in use by another program.")
518
+ foundDevices[k] = "DEVICE IN USE"
519
+
520
+ if (favouriteOnly):
521
+
522
+ # Sort list in order of connection type preference. Can be changed by changing position in conPref list. This must be done so that it is in the correct format for picking the favourite connections.
523
+ index = 0
524
+ sortedFoundDevices = {}
525
+ conPref = ["USB", "TCP", "SERIAL", "REST", "TELNET"]
526
+ while len(sortedFoundDevices) != len(foundDevices):
527
+ for k, v in foundDevices.items():
528
+ if conPref[index] in k:
529
+ sortedFoundDevices[k] = v
530
+ index += 1
531
+ foundDevices = sortedFoundDevices
532
+
533
+ # new dictionary only containing one favourite connection to each device.
534
+ favConFoundDevices = {}
535
+ index = 0
536
+ for k, v in sortedFoundDevices.items():
537
+ if (favConFoundDevices == {} or not v in favConFoundDevices.values()):
538
+ favConFoundDevices[k] = v
539
+ foundDevices = favConFoundDevices
540
+
541
+ # Sort by alphabetic order of key
542
+ sortedFoundDevices = {}
543
+ sortedFoundDevices = sorted(foundDevices.items(), key=operator.itemgetter(1))
544
+ foundDevices = dict(sortedFoundDevices)
545
+ if filterStr != None:
546
+ filteredDevices = {}
547
+ for k, v in foundDevices.items():
548
+ for j in filterStr:
549
+ if (j in v or "LOCKED MODULE" in v): #show locked modules too incase the module you are looking for is on the system but is locked
550
+ filteredDevices[k] = v
551
+ foundDevices = filteredDevices
552
+
553
+ # used to filter module via type ( Power / Drive / ...)
554
+ if module_type_filter:
555
+ foundDevices = filter_module_type(module_type_filter, foundDevices)
556
+
557
+ return foundDevices
558
+
559
+
560
+ '''
561
+ Prints out a list of Quarch devices nicely onto the terminal, numbering each unit
562
+ '''
563
+ def listDevices(scanDictionary):
564
+ if not scanDictionary:
565
+ printText("No quarch devices found to display")
566
+ else:
567
+ x = 1
568
+ for k, v in scanDictionary.items():
569
+ printText('{0:>3}'.format(str(x)) + " - " + '{0:<18}'.format(
570
+ v) + "\t" + k) # add padding to keep responses in line
571
+ x += 1
572
+
573
+
574
+ '''
575
+ Requests the user to select one of the devices in the given list
576
+ '''
577
+ def userSelectDevice(scanDictionary=None, scanFilterStr=None,favouriteOnly=True, message=None, title=None, nice=False, additionalOptions = None, target_conn="all"):
578
+ if User_interface.instance != None and User_interface.instance.selectedInterface == "testcenter":
579
+ nice = False
580
+ if message is None: message = "Please select a quarch device"
581
+ if title is None: title = "Select a Device"
582
+ ip_address = None
583
+ while (True):
584
+ # Scan first, if no list is supplied
585
+ if (scanDictionary is None):
586
+ printText("Scanning for devices...")
587
+ if ip_address == None:
588
+ scanDictionary = scanDevices(filterStr=scanFilterStr, favouriteOnly=favouriteOnly, target_conn=target_conn)
589
+ else:
590
+ scanDictionary = scanDevices(filterStr=scanFilterStr, favouriteOnly=favouriteOnly, target_conn=target_conn, ipAddressLookup=ip_address)
591
+
592
+ if len(scanDictionary)<1:
593
+ scanDictionary["***No Devices Found***"]="***No Devices Found***"
594
+
595
+
596
+ if nice: #Prepair the data for niceListSelection using displayTable().
597
+ if additionalOptions is None: additionalOptions = ["Specify IP Address","Rescan","Quit"]
598
+ tempList = []
599
+ tempEl = []
600
+ for k, v in scanDictionary.items():
601
+ tempEl = []
602
+ tempEl.append(v)
603
+ charPos = k.find(":")
604
+ tempEl.append(k)
605
+ tempList.append(tempEl)
606
+ adOp =[]
607
+ for option in additionalOptions:
608
+ adOp.append([option]*2) # Put option in all columns
609
+ #adOp.append([option,"-"])
610
+ userStr = listSelection(title, message, tempList, additionalOptions=adOp, indexReq=True, nice=nice, tableHeaders=["Selection", "Description"])
611
+ userStr = userStr[2] #With the data formatted in this way the ConnTarget will always be in userStr[2]
612
+
613
+ else: # Prepare data for old style selection or testCenter
614
+ devicesString = []
615
+ for k, v in scanDictionary.items():
616
+ charPos = k.find(":")
617
+ devicesString.append(k + '=' + v + ": " + k[:charPos])
618
+ devicesString = ','.join(devicesString)
619
+ if additionalOptions is None :
620
+ additionalOptions = "Specify IP Address=IP Scan,Rescan=Rescan,Quit=Quit"
621
+ userStr = listSelection(title=title,message=message,selectionList=devicesString, additionalOptions=additionalOptions)
622
+
623
+ # Process the user response
624
+ if (userStr.lower() in 'quit'):
625
+ return "quit"
626
+ elif (userStr.lower() in 'rescan'):
627
+ ip_address = None
628
+ scanDictionary = None
629
+ favouriteOnly = True
630
+ elif (userStr.lower() in 'all conn types'):
631
+ ip_address = None
632
+ scanDictionary = None
633
+ favouriteOnly = False
634
+ elif(userStr.lower() in 'specify ip address'):
635
+ ip_address = requestDialog("Please input IP Address of the module you would like to connect to: ")
636
+ scanDictionary = None
637
+ favouriteOnly = False
638
+ else:
639
+ # Return the address string of the selected module
640
+ return userStr
641
+
642
+
643
+ #TODO Remove all of this sb db
644
+ myDeviceString = userSelectDevice()
645
+ print(myDeviceString)
quarchpy/docs/CHANGES.rst CHANGED
@@ -13,6 +13,20 @@ Quarchpy
13
13
  Change Log
14
14
  ----------
15
15
 
16
+ 2.1.17
17
+ ------
18
+ - Improved QIS QPS launching on Linux sytems
19
+ - System debug for linux systems
20
+
21
+ 2.1.16
22
+ ------
23
+ - FIO mb/s parsing
24
+ - Improved QIS QPS launching
25
+
26
+ 2.1.15
27
+ ------
28
+ - minor bug fix
29
+
16
30
  2.1.14
17
31
  ------
18
32
  - minor bug fixes and logging improvements.