Coverage for /Users/Newville/Codes/xraylarch/larch/epics/xspress3.py: 23%
224 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1#!/usr/bin/python
2import sys
3import os
4import time
5from configparser import ConfigParser
7from epics import Device, caget, caput, poll
8from epics.devices.mca import MCA, ROI
9from .ad_mca import ADMCA, ADMCAROI
11MAX_ROIS = 48
13class ADFileMixin(object):
14 """mixin class for Xspress3"""
15 def filePut(self, attr, value, **kws):
16 return self.put("%s%s" % (self.filesaver, attr), value, **kws)
18 def fileGet(self, attr, **kws):
19 return self.get("%s%s" % (self.filesaver, attr), **kws)
21 def setFilePath(self, pathname):
22 fullpath = os.path.join(self.fileroot, pathname)
23 return self.filePut('FilePath', fullpath)
25 def setFileTemplate(self,fmt):
26 return self.filePut('FileTemplate', fmt)
28 def setFileWriteMode(self,mode):
29 return self.filePut('FileWriteMode', mode)
31 def setFileName(self,fname):
32 return self.filePut('FileName', fname)
34 def nextFileNumber(self):
35 self.setFileNumber(1+self.fileGet('FileNumber'))
37 def setFileNumber(self, fnum=None):
38 if fnum is None:
39 self.filePut('AutoIncrement', 1)
40 else:
41 self.filePut('AutoIncrement', 0)
42 return self.filePut('FileNumber',fnum)
44 def getLastFileName(self):
45 return self.fileGet('FullFileName_RBV',as_string=True)
47 def FileCaptureOn(self):
48 return self.filePut('Capture', 1)
50 def FileCaptureOff(self):
51 return self.filePut('Capture', 0)
53 def setFileNumCapture(self,n):
54 return self.filePut('NumCapture', n)
56 def FileWriteComplete(self):
57 return (0==self.fileGet('WriteFile_RBV') )
59 def getFileTemplate(self):
60 return self.fileGet('FileTemplate_RBV',as_string=True)
62 def getFileName(self):
63 return self.fileGet('FileName_RBV',as_string=True)
65 def getFileNumber(self):
66 return self.fileGet('FileNumber_RBV')
68 def getFilePath(self):
69 return self.fileGet('FilePath_RBV',as_string=True)
71 def getFileNameByIndex(self,index):
72 return self.getFileTemplate() % (self.getFilePath(), self.getFileName(), index)
74class Xspress3BaseMixin(object):
75 """xspress3 mixin -- triggers, acquire, etc"""
76 def useExternalTrigger(self):
77 self.TriggerMode = 3
79 def useInternalTrigger(self):
80 self.TriggerMode = 1
82 def setTriggerMode(self, mode):
83 self.TriggerMode = mode
85 def start(self, capture=True):
86 time.sleep(.05)
87 if capture:
88 self.FileCaptureOn()
89 self.Acquire = 1
91 def stop(self):
92 self.Acquire = 0
93 self.FileCaptureOff()
95 def get_rois(self):
96 return [m.get_rois() for m in self.mcas]
98class Xspress3(Device, ADFileMixin, Xspress3BaseMixin):
99 """Epics Xspress3.20 interface (with areaDetector2)"""
101 det_attrs = ('NumImages', 'NumImages_RBV', 'Acquire', 'Acquire_RBV',
102 'ArrayCounter_RBV', 'ERASE', 'UPDATE', 'AcquireTime',
103 'TriggerMode', 'StatusMessage_RBV', 'DetectorState_RBV')
105 _nonpvs = ('_prefix', '_pvs', '_delim', 'filesaver', 'fileroot',
106 'pathattrs', '_nonpvs', 'nmca', 'mcas')
108 pathattrs = ('FilePath', 'FileTemplate', 'FileName', 'FileNumber',
109 'Capture', 'NumCapture')
111 def __init__(self, prefix, nmca=4, filesaver='HDF1:',
112 fileroot='/home/xspress3/cars5/Data'):
113 if not prefix.endswith(':'):
114 prefix = "%s:" % prefix
115 self.nmca = nmca
116 attrs = []
117 attrs.extend(['%s%s' % (filesaver,p) for p in self.pathattrs])
119 self.filesaver = filesaver
120 self.fileroot = fileroot
121 self._prefix = prefix
122 self.mcas = []
123 for i in range(nmca):
124 imca = i+1
125 dprefix = "%sdet1:" % prefix
126 rprefix = "%sMCA%iROI" % (prefix, imca)
127 data_pv = "%sMCA%i:ArrayData" % (prefix, imca)
128 mca = ADMCA(dprefix, data_pv=data_pv, roi_prefix=rprefix)
129 self.mcas.append(mca)
131 Device.__init__(self, prefix, attrs=attrs, delim='')
132 for attr in self.det_attrs:
133 self.add_pv("%sdet1:%s" % (prefix, attr), attr)
134 for i in range(nmca):
135 imca = i+1
136 for j in range(10):
137 isca = j+1
138 attr="C%iSCA%i"% (imca, isca)
140 time.sleep(0.05)
142 def TimeSeriesCaptureOn(self, npts=None):
143 """ turns on a Time Series Capture"""
144 for imca in range(len(self.mcas)):
145 if npts is not None:
146 self._pvs["MCA%iTSNumPoints" % (imca+1)].put(npts)
147 self._pvs["SCA%iTSNumPoints" % (imca+1)].put(npts)
148 time.sleep(0.025)
149 for imca in range(len(self.mcas)):
150 self._pvs["MCA%iTSControl" % (imca+1)].put(0)
151 self._pvs["SCA%iTSControl" % (imca+1)].put(0)
153 def TimeSeriesCaptureOff(self):
154 """ turns off a Time Series Capture"""
155 for imca in range(len(self.mcas)):
156 self._pvs["MCA%iTSControl" % (imca+1)].put(2)
157 self._pvs["SCA%iTSControl" % (imca+1)].put(2)
159 def roi_calib_info(self):
160 buff = ['[rois]']
161 add = buff.append
162 rois = self.mcas[0].get_rois()
163 for iroi, roi in enumerate(rois):
164 name = roi.Name
165 hi = roi.MinX + roi.SizeX
166 if len(name.strip()) > 0 and hi > 0:
167 dbuff = []
168 for m in range(self.nmca):
169 dbuff.extend([roi.MinX, roi.MinX+roi.SizeX])
170 dbuff = ' '.join([str(i) for i in dbuff])
171 add("ROI%2.2i = %s | %s" % (iroi, name, dbuff))
173 add('[calibration]')
174 add("OFFSET = %s " % (' '.join(["0.000 "] * self.nmca)))
175 add("SLOPE = %s " % (' '.join(["0.010 "] * self.nmca)))
176 add("QUAD = %s " % (' '.join(["0.000 "] * self.nmca)))
177 add('[dxp]')
178 return buff
180 def restore_rois(self, roifile):
181 """restore ROI setting from ROI.dat file"""
182 cp = ConfigParser()
183 cp.read(roifile)
184 roidat = []
185 iroi = 0
186 for a in cp.options('rois'):
187 if a.lower().startswith('roi'):
188 name, dat = cp.get('rois', a).split('|')
189 lims = [int(i) for i in dat.split()]
190 lo, hi = lims[0], lims[1]
191 roidat.append((name.strip(), lo, hi))
193 for mca in self.mcas:
194 mca.set_rois(roidat)
196class Xspress310(Device, ADFileMixin, Xspress3BaseMixin):
197 """Epics Xspress3.10 interface (older version)"""
198 attrs = ('NumImages', 'NumImages_RBV',
199 'Acquire', 'Acquire_RBV',
200 'ArrayCounter_RBV',
201 'ERASE', 'UPDATE', 'AcquireTime',
202 'TriggerMode', 'StatusMessage_RBV',
203 'DetectorState_RBV')
205 _nonpvs = ('_prefix', '_pvs', '_delim', 'filesaver',
206 'fileroot', 'pathattrs', '_nonpvs', '_save_rois',
207 'nmca', 'dxps', 'mcas')
209 pathattrs = ('FilePath', 'FileTemplate',
210 'FileName', 'FileNumber',
211 'Capture', 'NumCapture')
213 def __init__(self, prefix, nmca=4, filesaver='HDF5:',
214 fileroot='/home/xspress3/cars5/Data'):
215 self.nmca = nmca
216 attrs = list(self.attrs)
217 attrs.extend(['%s%s' % (filesaver,p) for p in self.pathattrs])
219 self.filesaver = filesaver
220 self.fileroot = fileroot
221 self._prefix = prefix
222 self._save_rois = []
223 self.mcas = [MCA(prefix, mca=i+1) for i in range(nmca)]
225 Device.__init__(self, prefix, attrs=attrs, delim='')
226 time.sleep(0.1)
229 def select_rois_to_save(self, roilist):
230 """copy rois from MCA record to arrays to be saved
231 by XSPress3"""
232 roilist = list(roilist)
233 if len(roilist) < 4: roilist.append((50, 4050))
234 pref = self._prefix
235 self._save_rois = []
236 for iroi, roiname in enumerate(roilist):
237 label = roiname
238 if isinstance(roiname, tuple):
239 lo, hi = roiname
240 label = '[%i:%i]' % (lo, hi)
241 else:
242 rname = roiname.lower().strip()
243 lo, hi = 50, 4050
244 for ix in range(MAX_ROIS):
245 nm = caget('%smca1.R%iNM' % (pref, ix))
246 if nm.lower().strip() == rname:
247 lo = caget('%smca1.R%iLO' % (pref, ix))
248 hi = caget('%smca1.R%iHI' % (pref, ix))
249 break
250 self._save_rois.append(label)
251 for imca in range(1, self.nmca+1):
252 pv_lo = "%sC%i_MCA_ROI%i_LLM" % (pref, imca, iroi+1)
253 pv_hi = "%sC%i_MCA_ROI%i_HLM" % (pref, imca, iroi+1)
254 caput(pv_hi, hi)
255 caput(pv_lo, lo)
257 def roi_calib_info(self):
258 buff = ['[rois]']
259 add = buff.append
260 rois = self.get_rois()
261 for iroi in range(len(rois[0])):
262 name = rois[0][iroi].NM
263 hi = rois[0][iroi].HI
264 if len(name.strip()) > 0 and hi > 0:
265 dbuff = []
266 for m in range(self.nmca):
267 dbuff.extend([rois[m][iroi].LO, rois[m][iroi].HI])
268 dbuff = ' '.join([str(i) for i in dbuff])
269 add("ROI%2.2i = %s | %s" % (iroi, name, dbuff))
271 add('[calibration]')
272 add("OFFSET = %s " % (' '.join(["0.000 "] * self.nmca)))
273 add("SLOPE = %s " % (' '.join(["0.010 "] * self.nmca)))
274 add("QUAD = %s " % (' '.join(["0.000 "] * self.nmca)))
275 add('[dxp]')
276 return buff
278 def restore_rois(self, roifile):
279 """restore ROI setting from ROI.dat file"""
280 cp = ConfigParser()
281 cp.read(roifile)
282 rois = []
283 self.mcas[0].clear_rois()
284 prefix = self.mcas[0]._prefix
285 if prefix.endswith('.'):
286 prefix = prefix[:-1]
287 iroi = 0
288 for a in cp.options('rois'):
289 if a.lower().startswith('roi'):
290 name, dat = cp.get('rois', a).split('|')
291 lims = [int(i) for i in dat.split()]
292 lo, hi = lims[0], lims[1]
293 # print('ROI ', name, lo, hi)
294 roi = ROI(prefix=prefix, roi=iroi)
295 roi.LO = lo
296 roi.HI = hi
297 roi.NM = name.strip()
298 rois.append(roi)
299 iroi += 1
301 poll(0.050, 1.0)
302 self.mcas[0].set_rois(rois)
303 cal0 = self.mcas[0].get_calib()
304 for mca in self.mcas[1:]:
305 mca.set_rois(rois, calib=cal0)