newportxps 0.9__tar.gz → 2026.1.0__tar.gz
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.
- newportxps-2026.1.0/LICENSE +21 -0
- {newportxps-0.9/newportxps.egg-info → newportxps-2026.1.0}/PKG-INFO +9 -9
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/XPS_C8_drivers.py +3 -2
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/__init__.py +1 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/ftp_wrapper.py +37 -13
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/newportxps.py +128 -83
- newportxps-2026.1.0/newportxps/version.py +34 -0
- newportxps-2026.1.0/newportxps/xps_main.py +125 -0
- {newportxps-0.9 → newportxps-2026.1.0/newportxps.egg-info}/PKG-INFO +9 -9
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps.egg-info/SOURCES.txt +2 -0
- newportxps-2026.1.0/newportxps.egg-info/entry_points.txt +2 -0
- newportxps-2026.1.0/newportxps.egg-info/requires.txt +3 -0
- {newportxps-0.9 → newportxps-2026.1.0}/pyproject.toml +9 -7
- newportxps-0.9/LICENSE +0 -25
- newportxps-0.9/newportxps/version.py +0 -16
- newportxps-0.9/newportxps.egg-info/requires.txt +0 -2
- {newportxps-0.9 → newportxps-2026.1.0}/.gitignore +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/README.md +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/stages_XPSC.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/stages_XPSD.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/system_exA.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/system_exB.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/system_exC.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/examples/system_exD.ini +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/debugtime.py +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/debugtimer.py +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps/utils.py +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps.egg-info/dependency_links.txt +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/newportxps.egg-info/top_level.txt +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/setup.cfg +0 -0
- {newportxps-0.9 → newportxps-2026.1.0}/setup.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Matthew Newville, The University of Chicago
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
10
|
+
so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXP80RESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE qUSE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: newportxps
|
|
3
|
-
Version: 0
|
|
3
|
+
Version: 2026.1.0
|
|
4
4
|
Summary: Python interface to Newport XPS motion controllers
|
|
5
5
|
Author-email: Matthew Newville <newville@cars.uchicago.edu>
|
|
6
|
-
License:
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/pyepics/newportxps/
|
|
8
8
|
Keywords: motion control,data collection
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -11,16 +11,14 @@ Classifier: Intended Audience :: Developers
|
|
|
11
11
|
Classifier: Intended Audience :: Education
|
|
12
12
|
Classifier: Intended Audience :: Other Audience
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
15
14
|
Classifier: Operating System :: OS Independent
|
|
16
15
|
Classifier: Programming Language :: Python
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
-
Classifier: Programming Language :: Python ::
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
22
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
23
|
Classifier: Topic :: Education
|
|
26
24
|
Classifier: Topic :: Scientific/Engineering
|
|
@@ -29,11 +27,13 @@ Classifier: Topic :: Software Development
|
|
|
29
27
|
Classifier: Topic :: Software Development :: Libraries
|
|
30
28
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
29
|
Classifier: Topic :: Utilities
|
|
32
|
-
Requires-Python: >=3.
|
|
30
|
+
Requires-Python: >=3.10
|
|
33
31
|
Description-Content-Type: text/markdown
|
|
34
32
|
License-File: LICENSE
|
|
35
|
-
Requires-Dist:
|
|
33
|
+
Requires-Dist: paramiko
|
|
36
34
|
Requires-Dist: numpy
|
|
35
|
+
Requires-Dist: tabulate
|
|
36
|
+
Dynamic: license-file
|
|
37
37
|
|
|
38
38
|
# newportxps
|
|
39
39
|
|
|
@@ -91,6 +91,7 @@ class XPS:
|
|
|
91
91
|
# print("SEND REC ", command, type(command))
|
|
92
92
|
suffix = ',EndOfAPI'
|
|
93
93
|
try:
|
|
94
|
+
XPS.__sockets[socketId].settimeout(3600.0)
|
|
94
95
|
XPS.__sockets[socketId].send(str2bytes(command))
|
|
95
96
|
ret = bytes2str(XPS.__sockets[socketId].recv(1024))
|
|
96
97
|
while (ret.find(suffix) == -1):
|
|
@@ -1139,7 +1140,7 @@ class XPS:
|
|
|
1139
1140
|
def MultipleAxesPVTVerification (self, socketId, GroupName, TrajectoryFileName):
|
|
1140
1141
|
command = 'MultipleAxesPVTVerification(' + GroupName + ',' + TrajectoryFileName + ')'
|
|
1141
1142
|
return self.Send(socketId, command)
|
|
1142
|
-
|
|
1143
|
+
|
|
1143
1144
|
# MultipleAxesPTVerification : Multiple axes PT trajectory verification
|
|
1144
1145
|
def MultipleAxesPTVerification (self, socketId, GroupName, TrajectoryFileName):
|
|
1145
1146
|
command = 'MultipleAxesPTVerification(' + GroupName + ',' + TrajectoryFileName + ')'
|
|
@@ -1156,7 +1157,7 @@ class XPS:
|
|
|
1156
1157
|
def MultipleAxesPVTExecution (self, socketId, GroupName, TrajectoryFileName, ExecutionNumber):
|
|
1157
1158
|
command = 'MultipleAxesPVTExecution(' + GroupName + ',' + TrajectoryFileName + ',' + str(ExecutionNumber) + ')'
|
|
1158
1159
|
return self.Send(socketId, command)
|
|
1159
|
-
|
|
1160
|
+
|
|
1160
1161
|
# MultipleAxesPTExecution : Multiple axes PT trajectory execution
|
|
1161
1162
|
def MultipleAxesPTExecution (self, socketId, GroupName, TrajectoryFileName, ExecutionNumber):
|
|
1162
1163
|
command = 'MultipleAxesPTExecution(' + GroupName + ',' + TrajectoryFileName + ',' + str(ExecutionNumber) + ')'
|
|
@@ -9,6 +9,15 @@ logger = logging.getLogger('paramiko')
|
|
|
9
9
|
logger.setLevel(logging.ERROR)
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
SFTP_ERROR_MESSAGE = """Could not connect to XPS with sftp: no host key.
|
|
13
|
+
|
|
14
|
+
You may need to add a host key to your `ssh known_hosts` file, using
|
|
15
|
+
ssh-keyscan {host} >> ~/.ssh/known_hosts
|
|
16
|
+
|
|
17
|
+
or first connecting with `sftp Administrator@{host}` """
|
|
18
|
+
|
|
19
|
+
import paramiko
|
|
20
|
+
|
|
12
21
|
HAS_PYSFTP = False
|
|
13
22
|
try:
|
|
14
23
|
import pysftp
|
|
@@ -53,7 +62,9 @@ class FTPBaseWrapper(object):
|
|
|
53
62
|
class SFTPWrapper(FTPBaseWrapper):
|
|
54
63
|
"""wrap ftp interactions for Newport XPS models D"""
|
|
55
64
|
def __init__(self, host=None, username='Administrator',
|
|
56
|
-
password='Administrator'):
|
|
65
|
+
password='Administrator', use_paramiko=True):
|
|
66
|
+
self.use_paramiko = use_paramiko
|
|
67
|
+
self.ssh_client = None
|
|
57
68
|
FTPBaseWrapper.__init__(self, host=host,
|
|
58
69
|
username=username, password=password)
|
|
59
70
|
|
|
@@ -64,19 +75,32 @@ class SFTPWrapper(FTPBaseWrapper):
|
|
|
64
75
|
self.username = username
|
|
65
76
|
if password is not None:
|
|
66
77
|
self.password = password
|
|
78
|
+
if not self.use_paramiko and HAS_PYSFTP:
|
|
79
|
+
self._conn = pysftp.Connection(host,
|
|
80
|
+
username=username,
|
|
81
|
+
password=password)
|
|
82
|
+
else:
|
|
83
|
+
if self.ssh_client is None:
|
|
84
|
+
self.ssh_client = paramiko.SSHClient()
|
|
85
|
+
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
self.ssh_client.connect(host, 22, username, password)
|
|
89
|
+
|
|
90
|
+
except paramiko.AuthenticationException:
|
|
91
|
+
print("Authentication failed. Check your username and password/key.")
|
|
92
|
+
raise ValueError(SFTP_ERROR_MESSAGE.format(host=self.host))
|
|
93
|
+
except paramiko.SSHException as e:
|
|
94
|
+
print(f"SSH connection error: {e}")
|
|
95
|
+
raise ValueError(SFTP_ERROR_MESSAGE.format(host=self.host))
|
|
96
|
+
finally:
|
|
97
|
+
self._conn = self.ssh_client.open_sftp()
|
|
67
98
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
password=self.password)
|
|
74
|
-
except:
|
|
75
|
-
print("ERROR: sftp connection to %s failed" % self.host)
|
|
76
|
-
print("You may need to add the host keys for your XPS to your")
|
|
77
|
-
print("ssh known_hosts file, using a command like this:")
|
|
78
|
-
print(" ssh-keyscan %s >> ~/.ssh/known_hosts" % self.host)
|
|
79
|
-
|
|
99
|
+
def cwd(self, remotedir):
|
|
100
|
+
if self.use_paramiko:
|
|
101
|
+
self._conn.chdir(remotedir)
|
|
102
|
+
elif hasattr(self._conn, 'cwd'):
|
|
103
|
+
self._conn.cwd(remotedir)
|
|
80
104
|
|
|
81
105
|
def save(self, remotefile, localfile):
|
|
82
106
|
"save remote file to local file"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
|
|
3
3
|
import posixpath
|
|
4
|
+
import atexit
|
|
4
5
|
import sys
|
|
5
6
|
import time
|
|
6
7
|
import socket
|
|
@@ -28,7 +29,6 @@ def withConnectedXPS(fcn):
|
|
|
28
29
|
|
|
29
30
|
return wrapper
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
class NewportXPS:
|
|
33
33
|
gather_header = '# XPS Gathering Data\n#--------------'
|
|
34
34
|
def __init__(self, host, group=None,
|
|
@@ -88,19 +88,26 @@ class NewportXPS:
|
|
|
88
88
|
|
|
89
89
|
for groupname, status in self.get_group_status().items():
|
|
90
90
|
this = self.groups[groupname]
|
|
91
|
-
out.append(f"{groupname} ({this['category']}), Status: {status}")
|
|
91
|
+
out.append(f"#\n# {groupname} ({this['category']}), Status: {status}")
|
|
92
92
|
for pos in this['positioners']:
|
|
93
93
|
stagename = f"{groupname}.{pos}"
|
|
94
94
|
stage = self.stages[stagename]
|
|
95
|
-
out.extend([f"
|
|
95
|
+
out.extend([f" {stagename} ({stage['stagetype']})",
|
|
96
96
|
f" Hardware Status: {hstat[stagename]}",
|
|
97
97
|
f" Positioner Errors: {perrs[stagename]}"])
|
|
98
98
|
return "\n".join(out)
|
|
99
99
|
|
|
100
|
+
def disconnect(self):
|
|
101
|
+
self.ftpconn.close()
|
|
102
|
+
if self._sid is not None:
|
|
103
|
+
self._xps.TCP_CloseSocket(self._sid)
|
|
104
|
+
self._sid = None
|
|
100
105
|
|
|
101
106
|
def connect(self):
|
|
102
107
|
self._sid = self._xps.TCP_ConnectToServer(self.host,
|
|
103
108
|
self.port, self.timeout)
|
|
109
|
+
|
|
110
|
+
atexit.register(self.disconnect)
|
|
104
111
|
try:
|
|
105
112
|
self._xps.Login(self._sid, self.username, self.password)
|
|
106
113
|
except:
|
|
@@ -109,8 +116,7 @@ class NewportXPS:
|
|
|
109
116
|
err, val = self._xps.FirmwareVersionGet(self._sid)
|
|
110
117
|
self.firmware_version = val
|
|
111
118
|
self.ftphome = ''
|
|
112
|
-
|
|
113
|
-
if any([m in self.firmware_version for m in ['XPS-D', 'HXP-D']]):
|
|
119
|
+
if any([m in self.firmware_version for m in ['XPS-D', 'HXP-D', 'XPS-RL']]):
|
|
114
120
|
err, val = self._xps.Send(self._sid, 'InstallerVersionGet(char *)')
|
|
115
121
|
self.firmware_version = val
|
|
116
122
|
self.ftpconn = SFTPWrapper(**self.ftpargs)
|
|
@@ -120,6 +126,11 @@ class NewportXPS:
|
|
|
120
126
|
self.ftphome = '/Admin'
|
|
121
127
|
self.read_systemini()
|
|
122
128
|
|
|
129
|
+
def clean_folders(self):
|
|
130
|
+
if 'xps-d' in self.firmware_version.lower():
|
|
131
|
+
self._xps.CleanTmpFolder(self._sid)
|
|
132
|
+
self._xps.CleanCoreDumpFolder(self._sid)
|
|
133
|
+
|
|
123
134
|
|
|
124
135
|
def check_error(self, err, msg='', with_raise=True):
|
|
125
136
|
if err != 0:
|
|
@@ -168,7 +179,7 @@ class NewportXPS:
|
|
|
168
179
|
sconf.read_string(initext)
|
|
169
180
|
|
|
170
181
|
# read and populate lists of groups first
|
|
171
|
-
for gtype, glist in sconf.items('GROUPS'):
|
|
182
|
+
for gtype, glist in sconf.items('GROUPS'):
|
|
172
183
|
if len(glist) > 0:
|
|
173
184
|
for gname in glist.split(','):
|
|
174
185
|
gname = gname.strip()
|
|
@@ -191,21 +202,19 @@ class NewportXPS:
|
|
|
191
202
|
|
|
192
203
|
if len(pvtgroups) == 1:
|
|
193
204
|
self.set_trajectory_group(pvtgroups[0])
|
|
194
|
-
|
|
195
205
|
for sname in self.stages:
|
|
196
206
|
ret = self._xps.PositionerMaximumVelocityAndAccelerationGet(self._sid, sname)
|
|
197
207
|
try:
|
|
198
208
|
self.stages[sname]['max_velo'] = ret[1]
|
|
199
|
-
self.stages[sname]['max_accel'] = ret[2]
|
|
209
|
+
self.stages[sname]['max_accel'] = 0.75*ret[2]
|
|
200
210
|
except:
|
|
201
|
-
print(f"could not
|
|
211
|
+
print(f"could not read max velo/accel for {sname}")
|
|
202
212
|
ret = self._xps.PositionerUserTravelLimitsGet(self._sid, sname)
|
|
203
213
|
try:
|
|
204
214
|
self.stages[sname]['low_limit'] = ret[1]
|
|
205
215
|
self.stages[sname]['high_limit'] = ret[2]
|
|
206
216
|
except:
|
|
207
|
-
print(f"could not
|
|
208
|
-
|
|
217
|
+
print(f"could not read limits for {sname}")
|
|
209
218
|
return self.groups
|
|
210
219
|
|
|
211
220
|
def download_trajectory(self, filename):
|
|
@@ -426,8 +435,8 @@ class NewportXPS:
|
|
|
426
435
|
print(f"Warning: could not enable trajectory group '{self.traj_group}'")
|
|
427
436
|
return
|
|
428
437
|
|
|
429
|
-
for i in range(64):
|
|
430
|
-
|
|
438
|
+
#for i in range(64):
|
|
439
|
+
# self._xps.EventExtendedRemove(self._sid, i)
|
|
431
440
|
|
|
432
441
|
# build template for linear trajectory file:
|
|
433
442
|
trajline1 = ['%(ramptime)f']
|
|
@@ -630,8 +639,6 @@ class NewportXPS:
|
|
|
630
639
|
print("Do have a group to move")
|
|
631
640
|
return
|
|
632
641
|
ret = self._xps.GroupMoveAbort(self._sid, group)
|
|
633
|
-
print('abort group ', group, ret)
|
|
634
|
-
|
|
635
642
|
|
|
636
643
|
@withConnectedXPS
|
|
637
644
|
def move_group(self, group=None, **kws):
|
|
@@ -640,7 +647,7 @@ class NewportXPS:
|
|
|
640
647
|
if group is None or group not in self.groups:
|
|
641
648
|
group = self.traj_group
|
|
642
649
|
if group is None:
|
|
643
|
-
print("
|
|
650
|
+
print("no group to move")
|
|
644
651
|
return
|
|
645
652
|
posnames = [p.lower() for p in self.groups[group]['positioners']]
|
|
646
653
|
ret = self._xps.GroupPositionCurrentGet(self._sid, group, len(posnames))
|
|
@@ -742,8 +749,8 @@ class NewportXPS:
|
|
|
742
749
|
|
|
743
750
|
|
|
744
751
|
@withConnectedXPS
|
|
745
|
-
def define_line_trajectories(self, axis, group=None, pixeltime=
|
|
746
|
-
scantime=None, start=0, stop=1, step=0.
|
|
752
|
+
def define_line_trajectories(self, axis, group=None, pixeltime=None,
|
|
753
|
+
scantime=None, start=0, stop=1, step=0.01,
|
|
747
754
|
accel=None, upload=True, verbose=False):
|
|
748
755
|
"""defines 'forward' and 'backward' trajectories for a simple
|
|
749
756
|
single element line scan using PVT Mode
|
|
@@ -753,15 +760,14 @@ class NewportXPS:
|
|
|
753
760
|
|
|
754
761
|
if self.traj_group is None:
|
|
755
762
|
raise XPSException("No trajectory group defined")
|
|
756
|
-
|
|
763
|
+
# print(f"Define Line traj {axis=}, {self.traj_group=}")
|
|
757
764
|
for axname in (axis, axis.upper(), axis.lower(), axis.title()):
|
|
758
765
|
stage = f"{self.traj_group}.{axname}"
|
|
759
766
|
if stage in self.stages:
|
|
760
767
|
break
|
|
761
768
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
max_accel = 0.5*self.stages[stage]['max_accel']
|
|
769
|
+
max_velo = self.stages[stage]['max_velo']
|
|
770
|
+
max_accel = self.stages[stage]['max_accel']
|
|
765
771
|
|
|
766
772
|
if accel is None:
|
|
767
773
|
accel = max_accel
|
|
@@ -773,20 +779,24 @@ class NewportXPS:
|
|
|
773
779
|
step = scandir*abs(step)
|
|
774
780
|
|
|
775
781
|
npulses = int((abs(stop - start) + abs(step)*1.1) / abs(step))
|
|
776
|
-
if pixeltime is None
|
|
777
|
-
scantime
|
|
778
|
-
|
|
779
|
-
|
|
782
|
+
if pixeltime is None:
|
|
783
|
+
if scantime is None:
|
|
784
|
+
raise ValueError("line trajectory must set pixeltime or scantime")
|
|
785
|
+
else:
|
|
786
|
+
pixeltime = float(abs(scantime))/(npulses-1)
|
|
787
|
+
scantime = float(abs(pixeltime))*npulses
|
|
780
788
|
|
|
781
789
|
distance = (abs(stop - start) + abs(step))*1.0
|
|
782
790
|
velocity = min(distance/scantime, max_velo)
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
791
|
+
if verbose:
|
|
792
|
+
print(f"trajecory: {scantime=:.5f}, {pixeltime=:.5f}, {npulses=}, {start=:.5f}, {stop=:.5f}, {step=:.5f}")
|
|
793
|
+
ramptime = max(5.e-4, abs(velocity/accel))
|
|
794
|
+
rampdist = max(5.e-6, 0.5*velocity*ramptime)
|
|
795
|
+
offset = 0.5*step + scandir*rampdist
|
|
787
796
|
|
|
788
797
|
trajbase = {'axes': [axis],
|
|
789
798
|
'type': 'line',
|
|
799
|
+
'group': self.traj_group,
|
|
790
800
|
'pixeltime': pixeltime, 'uploaded': False,
|
|
791
801
|
'npulses': npulses+1, 'nsegments': 3}
|
|
792
802
|
|
|
@@ -828,6 +838,8 @@ class NewportXPS:
|
|
|
828
838
|
self.linear_template % back)
|
|
829
839
|
self.trajectories['foreward']['uploaded'] = True
|
|
830
840
|
self.trajectories['backward']['uploaded'] = True
|
|
841
|
+
self.trajectories['foreward']['text'] = self.linear_template % fore
|
|
842
|
+
self.trajectories['backward']['text'] = self.linear_template % back
|
|
831
843
|
ret = True
|
|
832
844
|
except:
|
|
833
845
|
raise ValueError("error uploading trajectory")
|
|
@@ -835,7 +847,7 @@ class NewportXPS:
|
|
|
835
847
|
|
|
836
848
|
@withConnectedXPS
|
|
837
849
|
def define_array_trajectory(self, positions, dtime=1.0, max_accels=None,
|
|
838
|
-
upload=True, name='array', verbose=True):
|
|
850
|
+
upload=True, name='array', group=None, verbose=True):
|
|
839
851
|
"""define a PVT trajectory for the trajectory group from a dictionary of
|
|
840
852
|
position arrays for each positioner in the trajectory group.
|
|
841
853
|
|
|
@@ -847,6 +859,7 @@ class NewportXPS:
|
|
|
847
859
|
dtime: float, time per segment
|
|
848
860
|
max_accels: dict of {PosName: max_acceleration} to use.
|
|
849
861
|
name: name of trajectory (file will be f"{name}.trj")
|
|
862
|
+
group: name of trajectory group
|
|
850
863
|
upload: bool, whether to upload trajectory
|
|
851
864
|
|
|
852
865
|
Returns:
|
|
@@ -868,6 +881,8 @@ class NewportXPS:
|
|
|
868
881
|
decelerate to zero velocity.
|
|
869
882
|
|
|
870
883
|
"""
|
|
884
|
+
if group is not None:
|
|
885
|
+
self.traj_group = group
|
|
871
886
|
tgroup = self.traj_group
|
|
872
887
|
if tgroup is None:
|
|
873
888
|
raise XPSException("No trajectory group defined")
|
|
@@ -951,9 +966,9 @@ class NewportXPS:
|
|
|
951
966
|
velo[axes] = np.zeros(npulses+1, dtype=np.float64)
|
|
952
967
|
accel[axes] = np.zeros(npulses+1, dtype=np.float64)
|
|
953
968
|
|
|
954
|
-
|
|
955
969
|
traj = {'axes': all_axes,
|
|
956
970
|
'type': 'array',
|
|
971
|
+
'group': self.traj_group,
|
|
957
972
|
'start': start, 'pixeltime': dtime,
|
|
958
973
|
'npulses': npulses+1, 'nsegments': npulses+1,
|
|
959
974
|
'uploaded': False}
|
|
@@ -966,7 +981,7 @@ class NewportXPS:
|
|
|
966
981
|
p, v = pos[axes][n], velo[axes][n]
|
|
967
982
|
line.extend([f"{p:.8f}", f"{v:.8f}"])
|
|
968
983
|
buff.append(', '.join(line))
|
|
969
|
-
|
|
984
|
+
buff.append('')
|
|
970
985
|
buff = '\n'.join(buff)
|
|
971
986
|
traj['pvt_buffer'] = buff
|
|
972
987
|
|
|
@@ -982,20 +997,32 @@ class NewportXPS:
|
|
|
982
997
|
return traj
|
|
983
998
|
|
|
984
999
|
|
|
1000
|
+
def get_trajectory(self, name, verify_group=True):
|
|
1001
|
+
"""get defined trajectory by name, with error checking"""
|
|
1002
|
+
traj = self.trajectories.get(name, None)
|
|
1003
|
+
if traj is None:
|
|
1004
|
+
raise XPSException(f"Cannot find trajectory named '{name}'")
|
|
1005
|
+
|
|
1006
|
+
if verify_group:
|
|
1007
|
+
traj_group = traj.get('group', self.traj_group)
|
|
1008
|
+
if traj_group != self.traj_group:
|
|
1009
|
+
raise XPSException(f"trajectory '{name}' uses group '{traj_group}', not '{self.traj_group=}'")
|
|
1010
|
+
return traj
|
|
1011
|
+
|
|
985
1012
|
@withConnectedXPS
|
|
986
|
-
def move_to_trajectory_start(self, name):
|
|
1013
|
+
def move_to_trajectory_start(self, name, group=None):
|
|
987
1014
|
"""
|
|
988
1015
|
move to the start position of a named trajectory
|
|
989
1016
|
"""
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
raise XPSException("No trajectory group defined")
|
|
1017
|
+
if group is not None:
|
|
1018
|
+
self.traj_group = group
|
|
993
1019
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
raise XPSException(f"Cannot find trajectory named '{name}'")
|
|
1020
|
+
if self.traj_group is None:
|
|
1021
|
+
raise XPSException("No trajectory group defined")
|
|
997
1022
|
|
|
1023
|
+
traj = self.get_trajectory(name, verify_group=True)
|
|
998
1024
|
if traj['type'] == 'line':
|
|
1025
|
+
tgroup = traj['group']
|
|
999
1026
|
for pos, axes in zip(traj['start'], traj['axes']):
|
|
1000
1027
|
self.move_stage(f'{tgroup}.{axes}', pos)
|
|
1001
1028
|
|
|
@@ -1004,30 +1031,26 @@ class NewportXPS:
|
|
|
1004
1031
|
if pos is not None:
|
|
1005
1032
|
self.move_stage(f'{tgroup}.{axes}', pos)
|
|
1006
1033
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
1034
|
@withConnectedXPS
|
|
1010
|
-
def arm_trajectory(self, name, verbose=False, move_to_start=True):
|
|
1035
|
+
def arm_trajectory(self, name, verbose=False, move_to_start=True, group=None):
|
|
1011
1036
|
"""
|
|
1012
1037
|
prepare to run a named (assumed uploaded) trajectory
|
|
1013
1038
|
"""
|
|
1039
|
+
if group is not None:
|
|
1040
|
+
self.traj_group = group
|
|
1041
|
+
|
|
1014
1042
|
if self.traj_group is None:
|
|
1015
1043
|
print("Must set group name!")
|
|
1016
1044
|
|
|
1017
|
-
traj = self.
|
|
1018
|
-
if traj is None:
|
|
1019
|
-
raise XPSException(f"Cannot find trajectory '{name}'")
|
|
1020
|
-
|
|
1045
|
+
traj = self.get_trajectory(name, verify_group=True)
|
|
1021
1046
|
if not traj['uploaded']:
|
|
1022
1047
|
raise XPSException(f"trajectory '{name}' has not been uploaded")
|
|
1023
1048
|
|
|
1024
|
-
|
|
1025
1049
|
self.traj_state = ARMING
|
|
1026
1050
|
self.traj_file = f'{name}.trj'
|
|
1027
1051
|
|
|
1028
1052
|
if move_to_start:
|
|
1029
1053
|
self.move_to_trajectory_start(name)
|
|
1030
|
-
|
|
1031
1054
|
# move_kws = {}
|
|
1032
1055
|
outputs = []
|
|
1033
1056
|
for out in self.gather_outputs:
|
|
@@ -1049,33 +1072,33 @@ class NewportXPS:
|
|
|
1049
1072
|
|
|
1050
1073
|
if verbose:
|
|
1051
1074
|
print(" GatheringConfigurationSet outputs ", outputs)
|
|
1052
|
-
print(" GatheringConfigurationSet returned ", ret)
|
|
1075
|
+
print(" GatheringConfigurationSet returned ", ret, time.ctime())
|
|
1053
1076
|
print(" segments, pixeltime" , end_segment, traj['pixeltime'])
|
|
1054
1077
|
|
|
1055
1078
|
err, ret = self._xps.MultipleAxesPVTPulseOutputSet(self._sid, self.traj_group,
|
|
1056
1079
|
2, end_segment,
|
|
1057
1080
|
traj['pixeltime'])
|
|
1058
|
-
self.check_error(err, msg="PVTPulseOutputSet", with_raise=
|
|
1081
|
+
self.check_error(err, msg="PVTPulseOutputSet", with_raise=True)
|
|
1059
1082
|
if verbose:
|
|
1060
|
-
print(" PVTPulse ", ret)
|
|
1083
|
+
print(" PVTPulse ", ret, time.ctime())
|
|
1061
1084
|
err, ret = self._xps.MultipleAxesPVTVerification(self._sid,
|
|
1062
1085
|
self.traj_group,
|
|
1063
1086
|
self.traj_file)
|
|
1064
1087
|
|
|
1065
|
-
self.check_error(err, msg="PVTVerification", with_raise=
|
|
1088
|
+
self.check_error(err, msg="PVTVerification", with_raise=True)
|
|
1066
1089
|
if verbose:
|
|
1067
|
-
print(" PVTVerify ", ret)
|
|
1090
|
+
print(" PVTVerify ", ret, time.ctime())
|
|
1068
1091
|
self.traj_state = ARMED
|
|
1069
1092
|
|
|
1070
1093
|
@withConnectedXPS
|
|
1071
|
-
def run_trajectory(self, name=None, save=True, clean=False,
|
|
1072
|
-
output_file='Gather.dat', verbose=False):
|
|
1094
|
+
def run_trajectory(self, name=None, save=True, clean=False, group=None,
|
|
1095
|
+
output_file='Gather.dat', verbose=False, move_to_start=True):
|
|
1073
1096
|
|
|
1074
1097
|
"""run a trajectory in PVT mode
|
|
1075
1098
|
|
|
1076
1099
|
The trajectory *must be in the ARMED state
|
|
1077
1100
|
"""
|
|
1078
|
-
|
|
1101
|
+
dt = debugtime()
|
|
1079
1102
|
if 'xps-d' in self.firmware_version.lower():
|
|
1080
1103
|
self._xps.CleanTmpFolder(self._sid)
|
|
1081
1104
|
|
|
@@ -1083,11 +1106,13 @@ class NewportXPS:
|
|
|
1083
1106
|
self._xps.CleanCoreDumpFolder(self._sid)
|
|
1084
1107
|
|
|
1085
1108
|
if name in self.trajectories and self.traj_state != ARMED:
|
|
1086
|
-
self.arm_trajectory(name, verbose=verbose
|
|
1109
|
+
self.arm_trajectory(name, verbose=verbose, group=group,
|
|
1110
|
+
move_to_start=move_to_start)
|
|
1087
1111
|
|
|
1088
1112
|
if self.traj_state != ARMED:
|
|
1089
1113
|
raise XPSException("Must arm trajectory before running!")
|
|
1090
1114
|
|
|
1115
|
+
dt.add('armed')
|
|
1091
1116
|
tgroup = self.traj_group
|
|
1092
1117
|
buffer = ('Always', f'{tgroup}.PVT.TrajectoryPulse',)
|
|
1093
1118
|
err, ret = self._xps.EventExtendedConfigurationTriggerSet(self._sid, buffer,
|
|
@@ -1096,35 +1121,46 @@ class NewportXPS:
|
|
|
1096
1121
|
self.check_error(err, msg="EventConfigTrigger")
|
|
1097
1122
|
if verbose:
|
|
1098
1123
|
print( " EventExtended Trigger Set ", ret)
|
|
1099
|
-
|
|
1124
|
+
dt.add('event trigger set')
|
|
1100
1125
|
err, ret = self._xps.EventExtendedConfigurationActionSet(self._sid,
|
|
1101
1126
|
('GatheringOneData',),
|
|
1102
1127
|
('',), ('',),('',),('',))
|
|
1103
1128
|
self.check_error(err, msg="EventConfigAction")
|
|
1104
1129
|
if verbose:
|
|
1105
1130
|
print( " EventExtended Action Set ", ret)
|
|
1106
|
-
|
|
1131
|
+
dt.add('event action set')
|
|
1107
1132
|
eventID, m = self._xps.EventExtendedStart(self._sid)
|
|
1108
1133
|
self.traj_state = RUNNING
|
|
1109
1134
|
|
|
1110
1135
|
if verbose:
|
|
1111
1136
|
print( " EventExtended ExtendedStart ", eventID, m)
|
|
1112
|
-
|
|
1137
|
+
dt.add('event start')
|
|
1113
1138
|
err, ret = self._xps.MultipleAxesPVTExecution(self._sid,
|
|
1114
1139
|
self.traj_group,
|
|
1115
1140
|
self.traj_file, 1)
|
|
1116
1141
|
self.check_error(err, msg="PVT Execute", with_raise=False)
|
|
1117
1142
|
if verbose:
|
|
1118
|
-
print( " PVT Execute
|
|
1119
|
-
|
|
1143
|
+
print( " PVT Execute done ", ret)
|
|
1144
|
+
dt.add('pvt execute')
|
|
1120
1145
|
ret = self._xps.EventExtendedRemove(self._sid, eventID)
|
|
1121
1146
|
ret = self._xps.GatheringStop(self._sid)
|
|
1122
|
-
|
|
1147
|
+
dt.add('gathering stop')
|
|
1123
1148
|
self.traj_state = COMPLETE
|
|
1124
1149
|
npulses = 0
|
|
1125
1150
|
if save:
|
|
1126
|
-
self.
|
|
1151
|
+
npulses, buff = self.read_gathering(set_idle_when_done=False,
|
|
1152
|
+
verbose=verbose)
|
|
1153
|
+
dt.add('read gathering')
|
|
1154
|
+
if npulses > 0:
|
|
1155
|
+
self.save_gathering_file(output_file, buff,
|
|
1156
|
+
verbose=verbose,
|
|
1157
|
+
set_idle_when_done=False)
|
|
1158
|
+
dt.add('saved gathering')
|
|
1159
|
+
self.ngathered = npulses
|
|
1160
|
+
# self.read_and_save(output_file, verbose=verbose)
|
|
1127
1161
|
self.traj_state = IDLE
|
|
1162
|
+
if verbose:
|
|
1163
|
+
dt.show()
|
|
1128
1164
|
return npulses
|
|
1129
1165
|
|
|
1130
1166
|
@withConnectedXPS
|
|
@@ -1156,16 +1192,18 @@ class NewportXPS:
|
|
|
1156
1192
|
t0 = time.time()
|
|
1157
1193
|
while npulses < 1:
|
|
1158
1194
|
try:
|
|
1159
|
-
|
|
1195
|
+
gdat = self._xps.GatheringCurrentNumberGet(self._sid)
|
|
1160
1196
|
except SyntaxError:
|
|
1161
1197
|
print("#XPS Gathering Read failed, will try again")
|
|
1162
|
-
|
|
1198
|
+
if len(gdat) == 3:
|
|
1199
|
+
ret, npulses, nx = gdat
|
|
1200
|
+
if npulses < 1 or ret != 0:
|
|
1201
|
+
time.sleep(0.1)
|
|
1202
|
+
|
|
1163
1203
|
if time.time()-t0 > 5:
|
|
1164
1204
|
print("Failed to get gathering size after 5 seconds: return 0 points")
|
|
1165
1205
|
print("Gather Returned: ", ret, npulses, nx, self._xps, time.ctime())
|
|
1166
1206
|
return (0, ' \n')
|
|
1167
|
-
if npulses < 1 or ret != 0:
|
|
1168
|
-
time.sleep(0.05)
|
|
1169
1207
|
dt.add("gather num %d npulses=%d (%d)" % (ret, npulses, self.nsegments))
|
|
1170
1208
|
counter = 0
|
|
1171
1209
|
while npulses < 1 and counter < 5:
|
|
@@ -1177,7 +1215,7 @@ class NewportXPS:
|
|
|
1177
1215
|
try:
|
|
1178
1216
|
ret, buff = self._xps.GatheringDataMultipleLinesGet(self._sid, 0, npulses)
|
|
1179
1217
|
except ValueError:
|
|
1180
|
-
print("Failed to read gathering: ", ret
|
|
1218
|
+
print("Failed to read gathering: ", ret)
|
|
1181
1219
|
return (0, ' \n')
|
|
1182
1220
|
dt.add("gather after multilinesget %d" % ret)
|
|
1183
1221
|
nchunks = -1
|
|
@@ -1231,11 +1269,17 @@ class NewportXPS:
|
|
|
1231
1269
|
start_values=None,
|
|
1232
1270
|
stop_values=None,
|
|
1233
1271
|
accel_values=None,
|
|
1234
|
-
pulse_time=0.1, scan_time=10.0):
|
|
1272
|
+
pulse_time=0.1, scan_time=10.0, group=None):
|
|
1235
1273
|
"""
|
|
1236
1274
|
Clemens' code for line trajectories -- should probably be
|
|
1237
1275
|
unified with define_line_trajectories(),
|
|
1238
1276
|
"""
|
|
1277
|
+
if group is not None:
|
|
1278
|
+
self.traj_group = group
|
|
1279
|
+
|
|
1280
|
+
if self.traj_group is None:
|
|
1281
|
+
raise XPSException("No trajectory group defined")
|
|
1282
|
+
|
|
1239
1283
|
if start_values is None:
|
|
1240
1284
|
start_values = np.zeros(len(self.traj_positioners))
|
|
1241
1285
|
else:
|
|
@@ -1264,7 +1308,6 @@ class NewportXPS:
|
|
|
1264
1308
|
|
|
1265
1309
|
ramp_time = 1.5 * max(abs(velocities / accel_values))
|
|
1266
1310
|
ramp = velocities * ramp_time
|
|
1267
|
-
print("ramp : ", ramp_time, ramp)
|
|
1268
1311
|
|
|
1269
1312
|
ramp_attr = {'ramptime': ramp_time}
|
|
1270
1313
|
down_attr = {'ramptime': ramp_time}
|
|
@@ -1302,6 +1345,7 @@ class NewportXPS:
|
|
|
1302
1345
|
trajectory_str += down_str + '\n'
|
|
1303
1346
|
|
|
1304
1347
|
self.trajectories[name] = {'pulse_time': pulse_time,
|
|
1348
|
+
'group': self.traj_group,
|
|
1305
1349
|
'step_number': len(distances)}
|
|
1306
1350
|
|
|
1307
1351
|
for ind, positioner in enumerate(self.traj_positioners):
|
|
@@ -1315,11 +1359,15 @@ class NewportXPS:
|
|
|
1315
1359
|
return trajectory_str
|
|
1316
1360
|
|
|
1317
1361
|
def run_line_trajectory_general(self, name='default', verbose=False, save=True,
|
|
1318
|
-
outfile='Gather.dat'):
|
|
1362
|
+
outfile='Gather.dat', group=None):
|
|
1319
1363
|
"""run trajectory in PVT mode"""
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1364
|
+
if group is not None:
|
|
1365
|
+
self.traj_group = group
|
|
1366
|
+
|
|
1367
|
+
if self.traj_group is None:
|
|
1368
|
+
raise XPSException("No trajectory group defined")
|
|
1369
|
+
|
|
1370
|
+
traj = self.get_trajectory(name, verify_group=True)
|
|
1323
1371
|
|
|
1324
1372
|
traj_file = f'{name}.trj'
|
|
1325
1373
|
dtime = traj['pulse_time']
|
|
@@ -1337,9 +1385,8 @@ class NewportXPS:
|
|
|
1337
1385
|
|
|
1338
1386
|
outputs = []
|
|
1339
1387
|
for out in self.gather_outputs:
|
|
1340
|
-
for
|
|
1388
|
+
for ax in traj['axes']:
|
|
1341
1389
|
outputs.append(f'{self.traj_group}.{ax}.{out}')
|
|
1342
|
-
# move_kws[ax] = float(traj['start'][i])
|
|
1343
1390
|
|
|
1344
1391
|
o = " ".join(outputs)
|
|
1345
1392
|
self.gather_titles = f"{self.gather_header}\n#{o}\n"
|
|
@@ -1350,7 +1397,7 @@ class NewportXPS:
|
|
|
1350
1397
|
2, step_number + 1, dtime)
|
|
1351
1398
|
self.check_error(err, msg="MultipleAxesPVTPulseOutputSet", with_raise=False)
|
|
1352
1399
|
|
|
1353
|
-
err,
|
|
1400
|
+
err, _ = self._xps.MultipleAxesPVTVerification(self._sid, self.traj_group, traj_file)
|
|
1354
1401
|
self.check_error(err, msg="MultipleAxesPVTVerification", with_raise=False)
|
|
1355
1402
|
|
|
1356
1403
|
buffer = ('Always', self.traj_group + '.PVT.TrajectoryPulse')
|
|
@@ -1363,7 +1410,7 @@ class NewportXPS:
|
|
|
1363
1410
|
('',), ('',), ('',), ('',))
|
|
1364
1411
|
self.check_error(err, msg="EventExtendedConfigurationActionSet", with_raise=False)
|
|
1365
1412
|
|
|
1366
|
-
eventID,
|
|
1413
|
+
eventID, _ = self._xps.EventExtendedStart(self._sid)
|
|
1367
1414
|
|
|
1368
1415
|
self._xps.MultipleAxesPVTExecution(self._sid, self.traj_group, traj_file, 1)
|
|
1369
1416
|
self._xps.EventExtendedRemove(self._sid, eventID)
|
|
@@ -1371,15 +1418,13 @@ class NewportXPS:
|
|
|
1371
1418
|
|
|
1372
1419
|
npulses = 0
|
|
1373
1420
|
if save:
|
|
1374
|
-
npulses,
|
|
1421
|
+
npulses, _ = self.read_and_save(outfile)
|
|
1375
1422
|
|
|
1376
1423
|
self._xps.GroupMoveRelative(self._sid, self.traj_group, ramps)
|
|
1377
1424
|
return npulses
|
|
1378
1425
|
|
|
1379
1426
|
|
|
1380
|
-
|
|
1381
1427
|
if __name__ == '__main__':
|
|
1382
|
-
import sys
|
|
1383
1428
|
ipaddr = sys.argv[1]
|
|
1384
1429
|
x = NewportXPS(ipaddr)
|
|
1385
1430
|
x.read_systemini()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '2026.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2026, 1, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = 'g3f4cc44e3'
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from argparse import ArgumentParser
|
|
5
|
+
from tabulate import tabulate
|
|
6
|
+
|
|
7
|
+
from .newportxps import NewportXPS
|
|
8
|
+
|
|
9
|
+
HELP_MESSAGE = """xps: simple interaction with NewportXPS controllers
|
|
10
|
+
xps -h shows this message.
|
|
11
|
+
xps [ADDR] status print status and configuration for XPS
|
|
12
|
+
xps [ADDR] groups print list of groups
|
|
13
|
+
xps [ADDR] reboot reboot xps
|
|
14
|
+
xps [ADDR] initialize [GROUP] initialize group by name
|
|
15
|
+
xps [ADDR] initialize_all initialize all group
|
|
16
|
+
xps [ADDR] home [GROUP] home group by name
|
|
17
|
+
xps [ADDR] home_all home all groups
|
|
18
|
+
xps [ADDR] get_system_ini [FILE] download system.ini to file
|
|
19
|
+
xps [ADDR] put_system_ini [FILE] upload system.ini from file
|
|
20
|
+
xps [ADDR] get_stages_ini [FILE] download stages.ini to file
|
|
21
|
+
xps [ADDR] put_stages_ini [FILE] upload stages.ini from file
|
|
22
|
+
|
|
23
|
+
ADDR: name or ip address for the controller
|
|
24
|
+
FILE: name of file to save or read
|
|
25
|
+
GROUP: name of group to initialize or home
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def xps_main():
|
|
29
|
+
parser = ArgumentParser(prog='xps', description='NewportXPS controllers',
|
|
30
|
+
add_help=False)
|
|
31
|
+
parser.add_argument('-h', '--help', dest='help', action='store_true',
|
|
32
|
+
default=False, help='show help')
|
|
33
|
+
parser.add_argument('options', nargs='*')
|
|
34
|
+
args = parser.parse_args()
|
|
35
|
+
|
|
36
|
+
if args.help or len(args.options) == 0:
|
|
37
|
+
print(HELP_MESSAGE)
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
ipaddr = args.options.pop(0)
|
|
41
|
+
command = args.options.pop(0)
|
|
42
|
+
_argu = ''
|
|
43
|
+
if len(args.options) > 0:
|
|
44
|
+
_argu = args.options.pop(0)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
this_xps = NewportXPS(ipaddr)
|
|
48
|
+
except XPSException:
|
|
49
|
+
print(f"cannot connect to NewportXPS at {ipaddr=}")
|
|
50
|
+
return
|
|
51
|
+
except Exception:
|
|
52
|
+
print(f"unknown error connecting to NewportXPS at {ipaddr=}")
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
if command == 'status':
|
|
56
|
+
print(this_xps.status_report())
|
|
57
|
+
elif command == 'groups':
|
|
58
|
+
headers =('Group Name', 'Positioners', 'Type')
|
|
59
|
+
dat = []
|
|
60
|
+
for gn, gd in this_xps.groups.items():
|
|
61
|
+
dat.append((gn, ', '.join(gd['positioners']), gd['category']))
|
|
62
|
+
print(tabulate(dat, headers))
|
|
63
|
+
elif command == 'initialize_all':
|
|
64
|
+
this_xps.initialize_allgroups()
|
|
65
|
+
elif command == 'initialize':
|
|
66
|
+
if len(_argu) < 1:
|
|
67
|
+
print("xps initialize needs a group name, or use `xps initialize_all`")
|
|
68
|
+
return
|
|
69
|
+
groupname = _argu
|
|
70
|
+
if groupname not in this_xps.groups.keys():
|
|
71
|
+
print(f"xps initialize needs a valid group name, one of {', '.join(this_xps.groups.keys())}")
|
|
72
|
+
return
|
|
73
|
+
this_xps.initialize_group(groupname)
|
|
74
|
+
elif command == 'home_all':
|
|
75
|
+
this_xps.homee_allgroups()
|
|
76
|
+
elif command == 'home':
|
|
77
|
+
if len(_argu) < 1:
|
|
78
|
+
print("xps home needs a group name, or use `xps home_all`")
|
|
79
|
+
return
|
|
80
|
+
groupname = _argu
|
|
81
|
+
if groupname not in this_xps.groups.keys():
|
|
82
|
+
print(f"xps home needs a valid group name, one of {', '.join(this_xps.groups.keys())}")
|
|
83
|
+
return
|
|
84
|
+
this_xps.home_group(groupname)
|
|
85
|
+
|
|
86
|
+
elif command == 'reboot':
|
|
87
|
+
print(f"rebooting {ipaddr}")
|
|
88
|
+
this_xps.reboot()
|
|
89
|
+
|
|
90
|
+
elif command == 'get_system_ini':
|
|
91
|
+
filename = _argu
|
|
92
|
+
if len(filename) < 1:
|
|
93
|
+
filename = f'system_{ipaddr}.ini'
|
|
94
|
+
this_xps.save_systemini(filename)
|
|
95
|
+
print(f"saved system.ini to {filename}")
|
|
96
|
+
|
|
97
|
+
elif command == 'get_stages_ini':
|
|
98
|
+
filename = _argu
|
|
99
|
+
if len(filename) < 1:
|
|
100
|
+
filename = f'stages_{ipaddr}.ini'
|
|
101
|
+
this_xps.save_stagesini(filename)
|
|
102
|
+
print(f"saved stages.ini to {filename}")
|
|
103
|
+
|
|
104
|
+
elif command == 'put_system_ini':
|
|
105
|
+
filename = _argu
|
|
106
|
+
if len(filename) < 1:
|
|
107
|
+
print("xps put_system_ini needs system.ini file")
|
|
108
|
+
return
|
|
109
|
+
text = open(filneme, 'r').read()
|
|
110
|
+
this_xps.upload_systemini(text)
|
|
111
|
+
print(f"uploaded text from {filename} as system.ini")
|
|
112
|
+
|
|
113
|
+
elif command == 'put_stages_ini':
|
|
114
|
+
filename = _argu
|
|
115
|
+
if len(filename) < 1:
|
|
116
|
+
print("xps put_stages_ini needs stages.ini file")
|
|
117
|
+
return
|
|
118
|
+
text = open(filneme, 'r').read()
|
|
119
|
+
this_xps.upload_stagesini(text)
|
|
120
|
+
print(f"uploaded text from {filename} as stages.ini")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == '__main__':
|
|
125
|
+
xps_main()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: newportxps
|
|
3
|
-
Version: 0
|
|
3
|
+
Version: 2026.1.0
|
|
4
4
|
Summary: Python interface to Newport XPS motion controllers
|
|
5
5
|
Author-email: Matthew Newville <newville@cars.uchicago.edu>
|
|
6
|
-
License:
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/pyepics/newportxps/
|
|
8
8
|
Keywords: motion control,data collection
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -11,16 +11,14 @@ Classifier: Intended Audience :: Developers
|
|
|
11
11
|
Classifier: Intended Audience :: Education
|
|
12
12
|
Classifier: Intended Audience :: Other Audience
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
15
14
|
Classifier: Operating System :: OS Independent
|
|
16
15
|
Classifier: Programming Language :: Python
|
|
17
16
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
-
Classifier: Programming Language :: Python ::
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
22
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
23
|
Classifier: Topic :: Education
|
|
26
24
|
Classifier: Topic :: Scientific/Engineering
|
|
@@ -29,11 +27,13 @@ Classifier: Topic :: Software Development
|
|
|
29
27
|
Classifier: Topic :: Software Development :: Libraries
|
|
30
28
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
29
|
Classifier: Topic :: Utilities
|
|
32
|
-
Requires-Python: >=3.
|
|
30
|
+
Requires-Python: >=3.10
|
|
33
31
|
Description-Content-Type: text/markdown
|
|
34
32
|
License-File: LICENSE
|
|
35
|
-
Requires-Dist:
|
|
33
|
+
Requires-Dist: paramiko
|
|
36
34
|
Requires-Dist: numpy
|
|
35
|
+
Requires-Dist: tabulate
|
|
36
|
+
Dynamic: license-file
|
|
37
37
|
|
|
38
38
|
# newportxps
|
|
39
39
|
|
|
@@ -17,8 +17,10 @@ newportxps/ftp_wrapper.py
|
|
|
17
17
|
newportxps/newportxps.py
|
|
18
18
|
newportxps/utils.py
|
|
19
19
|
newportxps/version.py
|
|
20
|
+
newportxps/xps_main.py
|
|
20
21
|
newportxps.egg-info/PKG-INFO
|
|
21
22
|
newportxps.egg-info/SOURCES.txt
|
|
22
23
|
newportxps.egg-info/dependency_links.txt
|
|
24
|
+
newportxps.egg-info/entry_points.txt
|
|
23
25
|
newportxps.egg-info/requires.txt
|
|
24
26
|
newportxps.egg-info/top_level.txt
|
|
@@ -16,13 +16,14 @@ authors = [
|
|
|
16
16
|
{name="Matthew Newville", email="newville@cars.uchicago.edu"},
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
-
dependencies = ['
|
|
19
|
+
dependencies = ['paramiko', 'numpy', 'tabulate']
|
|
20
20
|
description = "Python interface to Newport XPS motion controllers"
|
|
21
21
|
readme = "README.md"
|
|
22
|
-
requires-python = ">=3.
|
|
22
|
+
requires-python = ">=3.10"
|
|
23
23
|
keywords = ["motion control", "data collection"]
|
|
24
24
|
|
|
25
|
-
license =
|
|
25
|
+
license = "MIT"
|
|
26
|
+
license-files = ["LICENSE"]
|
|
26
27
|
|
|
27
28
|
classifiers = [
|
|
28
29
|
"Development Status :: 5 - Production/Stable",
|
|
@@ -30,16 +31,14 @@ classifiers = [
|
|
|
30
31
|
"Intended Audience :: Education",
|
|
31
32
|
"Intended Audience :: Other Audience",
|
|
32
33
|
"Intended Audience :: Science/Research",
|
|
33
|
-
"License :: OSI Approved :: BSD License",
|
|
34
34
|
"Operating System :: OS Independent",
|
|
35
35
|
"Programming Language :: Python",
|
|
36
36
|
"Programming Language :: Python :: 3",
|
|
37
|
-
"Programming Language :: Python :: 3.8",
|
|
38
|
-
"Programming Language :: Python :: 3.9",
|
|
39
37
|
"Programming Language :: Python :: 3.10",
|
|
40
38
|
"Programming Language :: Python :: 3.11",
|
|
41
39
|
"Programming Language :: Python :: 3.12",
|
|
42
|
-
"Programming Language :: Python ::
|
|
40
|
+
"Programming Language :: Python :: 3.13",
|
|
41
|
+
"Programming Language :: Python :: 3.14",
|
|
43
42
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
44
43
|
"Topic :: Education",
|
|
45
44
|
"Topic :: Scientific/Engineering",
|
|
@@ -53,3 +52,6 @@ classifiers = [
|
|
|
53
52
|
|
|
54
53
|
[project.urls]
|
|
55
54
|
Homepage = "https://github.com/pyepics/newportxps/"
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
xps = "newportxps:xps_main"
|
newportxps-0.9/LICENSE
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
BSD 2-Clause License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2018, Matthew Newville, The University of Chicago
|
|
4
|
-
All rights reserved.
|
|
5
|
-
|
|
6
|
-
Redistribution and use in source and binary forms, with or without
|
|
7
|
-
modification, are permitted provided that the following conditions are met:
|
|
8
|
-
|
|
9
|
-
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
-
list of conditions and the following disclaimer.
|
|
11
|
-
|
|
12
|
-
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
-
this list of conditions and the following disclaimer in the documentation
|
|
14
|
-
and/or other materials provided with the distribution.
|
|
15
|
-
|
|
16
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
20
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
21
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
22
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
24
|
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
25
|
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools_scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
TYPE_CHECKING = False
|
|
4
|
-
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple, Union
|
|
6
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
-
else:
|
|
8
|
-
VERSION_TUPLE = object
|
|
9
|
-
|
|
10
|
-
version: str
|
|
11
|
-
__version__: str
|
|
12
|
-
__version_tuple__: VERSION_TUPLE
|
|
13
|
-
version_tuple: VERSION_TUPLE
|
|
14
|
-
|
|
15
|
-
__version__ = version = '0.9'
|
|
16
|
-
__version_tuple__ = version_tuple = (0, 9)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|