newportxps 2025.1.0__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.
Files changed (28) hide show
  1. {newportxps-2025.1.0/newportxps.egg-info → newportxps-2026.1.0}/PKG-INFO +2 -1
  2. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/__init__.py +1 -0
  3. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/newportxps.py +55 -32
  4. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/version.py +3 -3
  5. newportxps-2026.1.0/newportxps/xps_main.py +125 -0
  6. {newportxps-2025.1.0 → newportxps-2026.1.0/newportxps.egg-info}/PKG-INFO +2 -1
  7. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps.egg-info/SOURCES.txt +2 -0
  8. newportxps-2026.1.0/newportxps.egg-info/entry_points.txt +2 -0
  9. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps.egg-info/requires.txt +1 -0
  10. {newportxps-2025.1.0 → newportxps-2026.1.0}/pyproject.toml +4 -1
  11. {newportxps-2025.1.0 → newportxps-2026.1.0}/.gitignore +0 -0
  12. {newportxps-2025.1.0 → newportxps-2026.1.0}/LICENSE +0 -0
  13. {newportxps-2025.1.0 → newportxps-2026.1.0}/README.md +0 -0
  14. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/stages_XPSC.ini +0 -0
  15. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/stages_XPSD.ini +0 -0
  16. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/system_exA.ini +0 -0
  17. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/system_exB.ini +0 -0
  18. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/system_exC.ini +0 -0
  19. {newportxps-2025.1.0 → newportxps-2026.1.0}/examples/system_exD.ini +0 -0
  20. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/XPS_C8_drivers.py +0 -0
  21. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/debugtime.py +0 -0
  22. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/debugtimer.py +0 -0
  23. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/ftp_wrapper.py +0 -0
  24. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps/utils.py +0 -0
  25. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps.egg-info/dependency_links.txt +0 -0
  26. {newportxps-2025.1.0 → newportxps-2026.1.0}/newportxps.egg-info/top_level.txt +0 -0
  27. {newportxps-2025.1.0 → newportxps-2026.1.0}/setup.cfg +0 -0
  28. {newportxps-2025.1.0 → newportxps-2026.1.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: newportxps
3
- Version: 2025.1.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
6
  License-Expression: MIT
@@ -32,6 +32,7 @@ Description-Content-Type: text/markdown
32
32
  License-File: LICENSE
33
33
  Requires-Dist: paramiko
34
34
  Requires-Dist: numpy
35
+ Requires-Dist: tabulate
35
36
  Dynamic: license-file
36
37
 
37
38
  # newportxps
@@ -1,3 +1,4 @@
1
1
  from .version import __version__, __version_tuple__
2
2
 
3
3
  from .newportxps import NewportXPS
4
+ from .xps_main import xps_main
@@ -29,7 +29,6 @@ def withConnectedXPS(fcn):
29
29
 
30
30
  return wrapper
31
31
 
32
-
33
32
  class NewportXPS:
34
33
  gather_header = '# XPS Gathering Data\n#--------------'
35
34
  def __init__(self, host, group=None,
@@ -89,11 +88,11 @@ class NewportXPS:
89
88
 
90
89
  for groupname, status in self.get_group_status().items():
91
90
  this = self.groups[groupname]
92
- out.append(f"{groupname} ({this['category']}), Status: {status}")
91
+ out.append(f"#\n# {groupname} ({this['category']}), Status: {status}")
93
92
  for pos in this['positioners']:
94
93
  stagename = f"{groupname}.{pos}"
95
94
  stage = self.stages[stagename]
96
- out.extend([f"# {stagename} ({stage['stagetype']})",
95
+ out.extend([f" {stagename} ({stage['stagetype']})",
97
96
  f" Hardware Status: {hstat[stagename]}",
98
97
  f" Positioner Errors: {perrs[stagename]}"])
99
98
  return "\n".join(out)
@@ -761,7 +760,7 @@ class NewportXPS:
761
760
 
762
761
  if self.traj_group is None:
763
762
  raise XPSException("No trajectory group defined")
764
-
763
+ # print(f"Define Line traj {axis=}, {self.traj_group=}")
765
764
  for axname in (axis, axis.upper(), axis.lower(), axis.title()):
766
765
  stage = f"{self.traj_group}.{axname}"
767
766
  if stage in self.stages:
@@ -790,13 +789,14 @@ class NewportXPS:
790
789
  distance = (abs(stop - start) + abs(step))*1.0
791
790
  velocity = min(distance/scantime, max_velo)
792
791
  if verbose:
793
- print(f"trajecory: {scantime=:.4f}, {pixeltime=:.4f}, {npulses=}, {start=:.4f}, {stop=:.4f}, {step=:.4f}")
794
- ramptime = max(2.e-5, abs(velocity/accel))
795
- rampdist = 0.5*velocity*ramptime
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)
796
795
  offset = 0.5*step + scandir*rampdist
797
796
 
798
797
  trajbase = {'axes': [axis],
799
798
  'type': 'line',
799
+ 'group': self.traj_group,
800
800
  'pixeltime': pixeltime, 'uploaded': False,
801
801
  'npulses': npulses+1, 'nsegments': 3}
802
802
 
@@ -847,7 +847,7 @@ class NewportXPS:
847
847
 
848
848
  @withConnectedXPS
849
849
  def define_array_trajectory(self, positions, dtime=1.0, max_accels=None,
850
- upload=True, name='array', verbose=True):
850
+ upload=True, name='array', group=None, verbose=True):
851
851
  """define a PVT trajectory for the trajectory group from a dictionary of
852
852
  position arrays for each positioner in the trajectory group.
853
853
 
@@ -859,6 +859,7 @@ class NewportXPS:
859
859
  dtime: float, time per segment
860
860
  max_accels: dict of {PosName: max_acceleration} to use.
861
861
  name: name of trajectory (file will be f"{name}.trj")
862
+ group: name of trajectory group
862
863
  upload: bool, whether to upload trajectory
863
864
 
864
865
  Returns:
@@ -880,6 +881,8 @@ class NewportXPS:
880
881
  decelerate to zero velocity.
881
882
 
882
883
  """
884
+ if group is not None:
885
+ self.traj_group = group
883
886
  tgroup = self.traj_group
884
887
  if tgroup is None:
885
888
  raise XPSException("No trajectory group defined")
@@ -963,9 +966,9 @@ class NewportXPS:
963
966
  velo[axes] = np.zeros(npulses+1, dtype=np.float64)
964
967
  accel[axes] = np.zeros(npulses+1, dtype=np.float64)
965
968
 
966
-
967
969
  traj = {'axes': all_axes,
968
970
  'type': 'array',
971
+ 'group': self.traj_group,
969
972
  'start': start, 'pixeltime': dtime,
970
973
  'npulses': npulses+1, 'nsegments': npulses+1,
971
974
  'uploaded': False}
@@ -994,20 +997,32 @@ class NewportXPS:
994
997
  return traj
995
998
 
996
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
+
997
1012
  @withConnectedXPS
998
- def move_to_trajectory_start(self, name):
1013
+ def move_to_trajectory_start(self, name, group=None):
999
1014
  """
1000
1015
  move to the start position of a named trajectory
1001
1016
  """
1002
- tgroup = self.traj_group
1003
- if tgroup is None:
1004
- raise XPSException("No trajectory group defined")
1017
+ if group is not None:
1018
+ self.traj_group = group
1005
1019
 
1006
- traj = self.trajectories.get(name, None)
1007
- if traj is None:
1008
- raise XPSException(f"Cannot find trajectory named '{name}'")
1020
+ if self.traj_group is None:
1021
+ raise XPSException("No trajectory group defined")
1009
1022
 
1023
+ traj = self.get_trajectory(name, verify_group=True)
1010
1024
  if traj['type'] == 'line':
1025
+ tgroup = traj['group']
1011
1026
  for pos, axes in zip(traj['start'], traj['axes']):
1012
1027
  self.move_stage(f'{tgroup}.{axes}', pos)
1013
1028
 
@@ -1016,23 +1031,21 @@ class NewportXPS:
1016
1031
  if pos is not None:
1017
1032
  self.move_stage(f'{tgroup}.{axes}', pos)
1018
1033
 
1019
-
1020
1034
  @withConnectedXPS
1021
- 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):
1022
1036
  """
1023
1037
  prepare to run a named (assumed uploaded) trajectory
1024
1038
  """
1039
+ if group is not None:
1040
+ self.traj_group = group
1041
+
1025
1042
  if self.traj_group is None:
1026
1043
  print("Must set group name!")
1027
1044
 
1028
- traj = self.trajectories.get(name, None)
1029
- if traj is None:
1030
- raise XPSException(f"Cannot find trajectory '{name}'")
1031
-
1045
+ traj = self.get_trajectory(name, verify_group=True)
1032
1046
  if not traj['uploaded']:
1033
1047
  raise XPSException(f"trajectory '{name}' has not been uploaded")
1034
1048
 
1035
-
1036
1049
  self.traj_state = ARMING
1037
1050
  self.traj_file = f'{name}.trj'
1038
1051
 
@@ -1078,7 +1091,7 @@ class NewportXPS:
1078
1091
  self.traj_state = ARMED
1079
1092
 
1080
1093
  @withConnectedXPS
1081
- def run_trajectory(self, name=None, save=True, clean=False,
1094
+ def run_trajectory(self, name=None, save=True, clean=False, group=None,
1082
1095
  output_file='Gather.dat', verbose=False, move_to_start=True):
1083
1096
 
1084
1097
  """run a trajectory in PVT mode
@@ -1093,7 +1106,8 @@ class NewportXPS:
1093
1106
  self._xps.CleanCoreDumpFolder(self._sid)
1094
1107
 
1095
1108
  if name in self.trajectories and self.traj_state != ARMED:
1096
- self.arm_trajectory(name, verbose=verbose, move_to_start=move_to_start)
1109
+ self.arm_trajectory(name, verbose=verbose, group=group,
1110
+ move_to_start=move_to_start)
1097
1111
 
1098
1112
  if self.traj_state != ARMED:
1099
1113
  raise XPSException("Must arm trajectory before running!")
@@ -1255,11 +1269,17 @@ class NewportXPS:
1255
1269
  start_values=None,
1256
1270
  stop_values=None,
1257
1271
  accel_values=None,
1258
- pulse_time=0.1, scan_time=10.0):
1272
+ pulse_time=0.1, scan_time=10.0, group=None):
1259
1273
  """
1260
1274
  Clemens' code for line trajectories -- should probably be
1261
1275
  unified with define_line_trajectories(),
1262
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
+
1263
1283
  if start_values is None:
1264
1284
  start_values = np.zeros(len(self.traj_positioners))
1265
1285
  else:
@@ -1288,7 +1308,6 @@ class NewportXPS:
1288
1308
 
1289
1309
  ramp_time = 1.5 * max(abs(velocities / accel_values))
1290
1310
  ramp = velocities * ramp_time
1291
- print("ramp : ", ramp_time, ramp)
1292
1311
 
1293
1312
  ramp_attr = {'ramptime': ramp_time}
1294
1313
  down_attr = {'ramptime': ramp_time}
@@ -1326,6 +1345,7 @@ class NewportXPS:
1326
1345
  trajectory_str += down_str + '\n'
1327
1346
 
1328
1347
  self.trajectories[name] = {'pulse_time': pulse_time,
1348
+ 'group': self.traj_group,
1329
1349
  'step_number': len(distances)}
1330
1350
 
1331
1351
  for ind, positioner in enumerate(self.traj_positioners):
@@ -1339,11 +1359,15 @@ class NewportXPS:
1339
1359
  return trajectory_str
1340
1360
 
1341
1361
  def run_line_trajectory_general(self, name='default', verbose=False, save=True,
1342
- outfile='Gather.dat'):
1362
+ outfile='Gather.dat', group=None):
1343
1363
  """run trajectory in PVT mode"""
1344
- traj = self.trajectories.get(name, None)
1345
- if traj is None:
1346
- raise XPSException(f'Cannot find trajectory named {name}')
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)
1347
1371
 
1348
1372
  traj_file = f'{name}.trj'
1349
1373
  dtime = traj['pulse_time']
@@ -1400,7 +1424,6 @@ class NewportXPS:
1400
1424
  return npulses
1401
1425
 
1402
1426
 
1403
-
1404
1427
  if __name__ == '__main__':
1405
1428
  ipaddr = sys.argv[1]
1406
1429
  x = NewportXPS(ipaddr)
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2025.1.0'
32
- __version_tuple__ = version_tuple = (2025, 1, 0)
31
+ __version__ = version = '2026.1.0'
32
+ __version_tuple__ = version_tuple = (2026, 1, 0)
33
33
 
34
- __commit_id__ = commit_id = 'gd77177eec'
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: newportxps
3
- Version: 2025.1.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
6
  License-Expression: MIT
@@ -32,6 +32,7 @@ Description-Content-Type: text/markdown
32
32
  License-File: LICENSE
33
33
  Requires-Dist: paramiko
34
34
  Requires-Dist: numpy
35
+ Requires-Dist: tabulate
35
36
  Dynamic: license-file
36
37
 
37
38
  # newportxps
@@ -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
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ xps = newportxps:xps_main
@@ -1,2 +1,3 @@
1
1
  paramiko
2
2
  numpy
3
+ tabulate
@@ -16,7 +16,7 @@ authors = [
16
16
  {name="Matthew Newville", email="newville@cars.uchicago.edu"},
17
17
  ]
18
18
 
19
- dependencies = ['paramiko', 'numpy']
19
+ dependencies = ['paramiko', 'numpy', 'tabulate']
20
20
  description = "Python interface to Newport XPS motion controllers"
21
21
  readme = "README.md"
22
22
  requires-python = ">=3.10"
@@ -52,3 +52,6 @@ classifiers = [
52
52
 
53
53
  [project.urls]
54
54
  Homepage = "https://github.com/pyepics/newportxps/"
55
+
56
+ [project.scripts]
57
+ xps = "newportxps:xps_main"
File without changes
File without changes
File without changes
File without changes
File without changes