BioImager  3.9.1
A .NET microscopy imaging library. Supports various microscopes by using imported libraries & GUI automation. Supported libraries include PriorĀ® & ZeissĀ® & all devices supported by Micromanager 2.0 and python-microscope.
Loading...
Searching...
No Matches
pvcam.py
1#!/usr/bin/env python3
2
3## Copyright (C) 2009 David Baddeley <d.baddeley@auckland.ac.nz>
4## Copyright (C) 2020 Mick Phillips <mick.phillips@gmail.com>
5##
6## This file is part of Microscope.
7##
8## Microscope is free software: you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation, either version 3 of the License, or
11## (at your option) any later version.
12##
13## Microscope is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
20
21## The implementation of dllFunc is based on the implementation in
22## PYME, hence copyright to David Baddeley.
23
24"""pvcam library wrapper.
25
26This module exposes pvcam C library functions in python.
27
28.. todo::
29 Support frame metadata. The following functions are still not implemented::
30
31 /*****************************************************************************/
32 /*****************************************************************************/
33 /* */
34 /* Frame metadata functions */
35 /* */
36 /*****************************************************************************/
37 /*****************************************************************************/
38
39 /**
40 Decodes all the raw frame buffer metadata into a friendly structure.
41 @param pDstFrame A pre-allocated helper structure that will be filled with
42 information from the given raw buffer.
43 @param pSrcBuf A raw frame buffer as retrieved from PVCAM
44 @param srcBufSize The size of the raw frame buffer
45 @return #PV_FAIL in case of failure.
46 */
47 rs_bool PV_DECL pl_md_frame_decode (md_frame* pDstFrame, void* pSrcBuf, uns32 srcBufSize);
48
49 /**
50 Optional function that recomposes a multi-ROI frame into a displayable image buffer.
51 Every ROI will be copied into its appropriate location in the provided buffer.
52 Please note that the function will subtract the Implied ROI position from each ROI
53 position which essentially moves the entire Implied ROI to a [0, 0] position.
54 Use the Offset arguments to shift all ROIs back to desired positions if needed.
55 If you use the Implied ROI position for offset arguments the frame will be recomposed
56 as it appears on the full frame.
57 The caller is responsible for black-filling the input buffer. Usually this function
58 is called during live/preview mode where the destination buffer is re-used. If the
59 ROIs do move during acquisition it is essential to black-fill the destination buffer
60 before calling this function. This is not needed if the ROIs do not move.
61 If the ROIs move during live mode it is also recommended to use the offset arguments
62 and recompose the ROI to a full frame - with moving ROIs the implied ROI may change
63 with each frame and this may cause undesired ROI "twitching" in the displayable image.
64
65 @param pDstBuf An output buffer, the buffer must be at least the size of the implied
66 ROI that is calculated during the frame decoding process. The buffer
67 must be of type uns16. If offset is set the buffer must be large
68 enough to allow the entire implied ROI to be shifted.
69 @param offX Offset in the destination buffer, in pixels. If 0 the Implied
70 ROI will be shifted to position 0 in the target buffer.
71 Use (ImpliedRoi.s1 / ImplierRoi.sbin) as offset value to
72 disable the shift and keep the ROIs in their absolute positions.
73 @param offY Offset in the destination buffer, in pixels. If 0 the Implied
74 ROI will be shifted to position 0 in the target buffer.
75 Use (ImpliedRoi.p1 / ImplierRoi.pbin) as offset value to
76 disable the shift and keep the ROIs in their absolute positions.
77 @param dstWidth Width, in pixels of the destination image buffer. The buffer
78 must be large enough to hold the entire Implied ROI, including
79 the offsets (if used).
80 @param dstHeight Height, in pixels of the destination image buffer.
81 @param pSrcFrame A helper structure, previously decoded using the frame
82 decoding function.
83 @return #PV_FAIL in case of failure.
84 */
85 rs_bool PV_DECL pl_md_frame_recompose (void* pDstBuf, uns16 offX, uns16 offY,
86 uns16 dstWidth, uns16 dstHeight,
87 md_frame* pSrcFrame);
88
89 /**
90 This method creates an empty md_frame structure for known number of ROIs.
91 Use this method to prepare and pre-allocate one structure before starting
92 continous acquisition. Once callback arrives fill the structure with
93 pl_md_frame_decode() and display the metadata.
94 Release the structure when not needed.
95 @param pFrame a pointer to frame helper structure address where the structure
96 will be allocated.
97 @param roiCount Number of ROIs the structure should be prepared for.
98 @return #PV_FAIL in case of failure.
99 */
100 rs_bool PV_DECL pl_md_create_frame_struct_cont (md_frame** pFrame, uns16 roiCount);
101
102 /**
103 This method creates an empty md_frame structure from an existing buffer.
104 Use this method when loading buffers from disk or when performance is not
105 critical. Do not forget to release the structure when not needed.
106 For continous acquisition where the number or ROIs is known it is recommended
107 to use the other provided method to avoid frequent memory allocation.
108 @param pFrame A pointer address where the newly created structure will be stored.
109 @param pSrcBuf A raw frame data pointer as returned from the camera
110 @param srcBufSize Size of the raw frame data buffer
111 @return #PV_FAIL in case of failure
112 */
113 rs_bool PV_DECL pl_md_create_frame_struct (md_frame** pFrame, void* pSrcBuf,
114 uns32 srcBufSize);
115
116 /**
117 Releases the md_frame struct
118 @param pFrame a pointer to the previously allocated structure
119 */
120 rs_bool PV_DECL pl_md_release_frame_struct (md_frame* pFrame);
121
122 /**
123 Reads all the extended metadata from the given ext. metadata buffer.
124 @param pOutput A pre-allocated structure that will be filled with metadata
125 @param pExtMdPtr A pointer to the ext. MD buffer, this can be obtained from
126 the md_frame and md_frame_roi structures.
127 @param extMdSize Size of the ext. MD buffer, also retrievable from the helper
128 structures.
129 @return #PV_FAIL in case the metadata cannot be decoded.
130 */
131 rs_bool PV_DECL pl_md_read_extended (md_ext_item_collection* pOutput, void* pExtMdPtr,
132 uns32 extMdSize);
133
134"""
135
136import ctypes
137import logging
138import os
139import platform
140import time
141import weakref
142
143import numpy as np
144import Pyro4
145
146import microscope
147import microscope.abc
148
149
150_logger = logging.getLogger(__name__)
151
152
153# Readout transform mapping - {CHIP_NAME: {port: transform}}
154READOUT_TRANSFORMS = {"Evolve-5": {0: (0, 0, 0), 1: (1, 0, 0)}}
155
156# === Data types ===
157# Base typedefs, from pvcam SDK master.h
158# typedef unsigned short rs_bool;
159rs_bool = ctypes.c_ushort
160# typedef signed char int8;
161int8 = ctypes.c_byte
162# typedef unsigned char uns8;
163uns8 = ctypes.c_ubyte
164# typedef short int16;
165int16 = ctypes.c_short
166# typedef unsigned short uns16;
167uns16 = ctypes.c_ushort
168# typedef int int32;
169int32 = ctypes.c_int32
170# typedef unsigned int uns32;
171uns32 = ctypes.c_uint32
172# typedef float flt32;
173flt32 = ctypes.c_float
174# typedef double flt64;
175flt64 = ctypes.c_double
176# typedef unsigned long long ulong64;
177ulong64 = ctypes.c_ulonglong
178# typedef signed long long long64;
179long64 = ctypes.c_longlong
180# enums
181enumtype = ctypes.c_int32
182
183
184# defines, typedefs and enums parsed from pvcam.h .
185MAX_CAM = 16
186CAM_NAME_LEN = 32
187PARAM_NAME_LEN = 32
188ERROR_MSG_LEN = 255
189CCD_NAME_LEN = 17
190MAX_ALPHA_SER_NUM_LEN = 32
191MAX_PP_NAME_LEN = 32
192MAX_SYSTEM_NAME_LEN = 32
193MAX_VENDOR_NAME_LEN = 32
194MAX_PRODUCT_NAME_LEN = 32
195MAX_CAM_PART_NUM_LEN = 32
196MAX_GAIN_NAME_LEN = 32
197OPEN_EXCLUSIVE = 0
198NORMAL_COOL = 0
199CRYO_COOL = 1
200MPP_UNKNOWN = 0
201MPP_ALWAYS_OFF = 1
202MPP_ALWAYS_ON = 2
203MPP_SELECTABLE = 3
204SHTR_FAULT = 0
205SHTR_OPENING = 1
206SHTR_OPEN = 2
207SHTR_CLOSING = 3
208SHTR_CLOSED = 4
209SHTR_UNKNOWN = 5
210PMODE_NORMAL = 0
211PMODE_FT = 1
212PMODE_MPP = 2
213PMODE_FT_MPP = 3
214PMODE_ALT_NORMAL = 4
215PMODE_ALT_FT = 5
216PMODE_ALT_MPP = 6
217PMODE_ALT_FT_MPP = 7
218COLOR_NONE = 0
219COLOR_RESERVED = 1
220COLOR_RGGB = 2
221COLOR_GRBG = 3
222COLOR_GBRG = 4
223COLOR_BGGR = 5
224ATTR_CURRENT = 0
225ATTR_COUNT = 1
226ATTR_TYPE = 2
227ATTR_MIN = 3
228ATTR_MAX = 4
229ATTR_DEFAULT = 5
230ATTR_INCREMENT = 6
231ATTR_ACCESS = 7
232ATTR_AVAIL = 8
233ACC_READ_ONLY = 1
234ACC_READ_WRITE = 2
235ACC_EXIST_CHECK_ONLY = 3
236ACC_WRITE_ONLY = 4
237IO_TYPE_TTL = 0
238IO_TYPE_DAC = 1
239IO_DIR_INPUT = 0
240IO_DIR_OUTPUT = 1
241IO_DIR_INPUT_OUTPUT = 2
242READOUT_PORT_0 = 0
243READOUT_PORT_1 = 1
244CLEAR_NEVER = 0
245CLEAR_PRE_EXPOSURE = 1
246CLEAR_PRE_SEQUENCE = 2
247CLEAR_POST_SEQUENCE = 3
248CLEAR_PRE_POST_SEQUENCE = 4
249CLEAR_PRE_EXPOSURE_POST_SEQ = 5
250MAX_CLEAR_MODE = 6
251OPEN_NEVER = 0
252OPEN_PRE_EXPOSURE = 1
253OPEN_PRE_SEQUENCE = 2
254OPEN_PRE_TRIGGER = 3
255OPEN_NO_CHANGE = 4
256TIMED_MODE = 0
257STROBED_MODE = 1
258BULB_MODE = 2
259TRIGGER_FIRST_MODE = 3
260FLASH_MODE = 4
261VARIABLE_TIMED_MODE = 5
262INT_STROBE_MODE = 6
263MAX_EXPOSE_MODE = 7
264Extended = 8
265camera = 9
266The = 10
267definition = 11
268EXT_TRIG_INTERNAL = 12
269EXT_TRIG_TRIG_FIRST = 13
270EXT_TRIG_EDGE_RISING = 14
271EXPOSE_OUT_FIRST_ROW = 0
272EXPOSE_OUT_ALL_ROWS = 1
273EXPOSE_OUT_ANY_ROW = 2
274MAX_EXPOSE_OUT_MODE = 3
275FAN_SPEED_HIGH = 0
276FAN_SPEED_MEDIUM = 1
277FAN_SPEED_LOW = 2
278FAN_SPEED_OFF = 3
279PL_TRIGTAB_SIGNAL_EXPOSE_OUT = 0
280PP_FEATURE_RING_FUNCTION = 0
281PP_FEATURE_BIAS = 1
282PP_FEATURE_BERT = 2
283PP_FEATURE_QUANT_VIEW = 3
284PP_FEATURE_BLACK_LOCK = 4
285PP_FEATURE_TOP_LOCK = 5
286PP_FEATURE_VARI_BIT = 6
287PP_FEATURE_RESERVED = 7
288PP_FEATURE_DESPECKLE_BRIGHT_HIGH = 8
289PP_FEATURE_DESPECKLE_DARK_LOW = 9
290PP_FEATURE_DEFECTIVE_PIXEL_CORRECTION = 10
291PP_FEATURE_DYNAMIC_DARK_FRAME_CORRECTION = 11
292PP_FEATURE_HIGH_DYNAMIC_RANGE = 12
293PP_FEATURE_DESPECKLE_BRIGHT_LOW = 13
294PP_FEATURE_DENOISING = 14
295PP_FEATURE_DESPECKLE_DARK_HIGH = 15
296PP_FEATURE_ENHANCED_DYNAMIC_RANGE = 16
297PP_FEATURE_MAX = 17
298PP_MAX_PARAMETERS_PER_FEATURE = 10
299PP_PARAMETER_RF_FUNCTION = 0
300PP_FEATURE_BIAS_ENABLED = 1
301PP_FEATURE_BIAS_LEVEL = 2
302PP_FEATURE_BERT_ENABLED = 3
303PP_FEATURE_BERT_THRESHOLD = 4
304PP_FEATURE_QUANT_VIEW_ENABLED = 5
305PP_FEATURE_QUANT_VIEW_E = 6
306PP_FEATURE_BLACK_LOCK_ENABLED = 7
307PP_FEATURE_BLACK_LOCK_BLACK_CLIP = 8
308PP_FEATURE_TOP_LOCK_ENABLED = 9
309PP_FEATURE_TOP_LOCK_WHITE_CLIP = 10
310PP_FEATURE_VARI_BIT_ENABLED = 11
311PP_FEATURE_VARI_BIT_BIT_DEPTH = 12
312PP_FEATURE_DESPECKLE_BRIGHT_HIGH_ENABLED = 13
313PP_FEATURE_DESPECKLE_BRIGHT_HIGH_THRESHOLD = 14
314PP_FEATURE_DESPECKLE_BRIGHT_HIGH_MIN_ADU_AFFECTED = 15
315PP_FEATURE_DESPECKLE_DARK_LOW_ENABLED = 16
316PP_FEATURE_DESPECKLE_DARK_LOW_THRESHOLD = 17
317PP_FEATURE_DESPECKLE_DARK_LOW_MAX_ADU_AFFECTED = 18
318PP_FEATURE_DEFECTIVE_PIXEL_CORRECTION_ENABLED = 19
319PP_FEATURE_DYNAMIC_DARK_FRAME_CORRECTION_ENABLED = 20
320PP_FEATURE_HIGH_DYNAMIC_RANGE_ENABLED = 21
321PP_FEATURE_DESPECKLE_BRIGHT_LOW_ENABLED = 22
322PP_FEATURE_DESPECKLE_BRIGHT_LOW_THRESHOLD = 23
323PP_FEATURE_DESPECKLE_BRIGHT_LOW_MAX_ADU_AFFECTED = 24
324PP_FEATURE_DENOISING_ENABLED = 25
325PP_FEATURE_DENOISING_NO_OF_ITERATIONS = 26
326PP_FEATURE_DENOISING_GAIN = 27
327PP_FEATURE_DENOISING_OFFSET = 28
328PP_FEATURE_DENOISING_LAMBDA = 29
329PP_FEATURE_DESPECKLE_DARK_HIGH_ENABLED = 30
330PP_FEATURE_DESPECKLE_DARK_HIGH_THRESHOLD = 31
331PP_FEATURE_DESPECKLE_DARK_HIGH_MIN_ADU_AFFECTED = 32
332PP_FEATURE_ENHANCED_DYNAMIC_RANGE_ENABLED = 33
333PP_PARAMETER_ID_MAX = 34
334SMTMODE_ARBITRARY_ALL = 0
335SMTMODE_MAX = 1
336READOUT_NOT_ACTIVE = 0
337EXPOSURE_IN_PROGRESS = 1
338READOUT_IN_PROGRESS = 2
339READOUT_COMPLETE = 3
340FRAME_AVAILABLE = 3
341READOUT_FAILED = 4
342ACQUISITION_IN_PROGRESS = 5
343MAX_CAMERA_STATUS = 6
344CCS_NO_CHANGE = 0
345CCS_HALT = 1
346CCS_HALT_CLOSE_SHTR = 2
347CCS_CLEAR = 3
348CCS_CLEAR_CLOSE_SHTR = 4
349CCS_OPEN_SHTR = 5
350CCS_CLEAR_OPEN_SHTR = 6
351NO_FRAME_IRQS = 0
352BEGIN_FRAME_IRQS = 1
353END_FRAME_IRQS = 2
354BEGIN_END_FRAME_IRQS = 3
355CIRC_NONE = 0
356CIRC_OVERWRITE = 1
357CIRC_NO_OVERWRITE = 2
358EXP_RES_ONE_MILLISEC = 0
359EXP_RES_ONE_MICROSEC = 1
360EXP_RES_ONE_SEC = 2
361SCR_PRE_OPEN_SHTR = 0
362SCR_POST_OPEN_SHTR = 1
363SCR_PRE_FLASH = 2
364SCR_POST_FLASH = 3
365SCR_PRE_INTEGRATE = 4
366SCR_POST_INTEGRATE = 5
367SCR_PRE_READOUT = 6
368SCR_POST_READOUT = 7
369SCR_PRE_CLOSE_SHTR = 8
370SCR_POST_CLOSE_SHTR = 9
371PL_CALLBACK_BOF = 0
372PL_CALLBACK_EOF = 1
373PL_CALLBACK_CHECK_CAMS = 2
374PL_CALLBACK_CAM_REMOVED = 3
375PL_CALLBACK_CAM_RESUMED = 4
376PL_CALLBACK_MAX = 5
377PL_MD_FRAME_FLAG_ROI_TS_SUPPORTED = 1
378PL_MD_FRAME_FLAG_UNUSED_2 = 2
379PL_MD_FRAME_FLAG_UNUSED_3 = 4
380PL_MD_FRAME_FLAG_UNUSED_4 = 16
381PL_MD_FRAME_FLAG_UNUSED_5 = 32
382PL_MD_FRAME_FLAG_UNUSED_6 = 64
383PL_MD_FRAME_FLAG_UNUSED_7 = 128
384PL_MD_ROI_FLAG_INVALID = 1
385PL_MD_ROI_FLAG_UNUSED_2 = 2
386PL_MD_ROI_FLAG_UNUSED_3 = 4
387PL_MD_ROI_FLAG_UNUSED_4 = 16
388PL_MD_ROI_FLAG_UNUSED_5 = 32
389PL_MD_ROI_FLAG_UNUSED_6 = 64
390PL_MD_ROI_FLAG_UNUSED_7 = 128
391PL_MD_FRAME_SIGNATURE = 5328208
392PL_MD_EXT_TAGS_MAX_SUPPORTED = 255
393PL_MD_EXT_TAG_MAX = 0
394TYPE_INT16 = 1
395TYPE_INT32 = 2
396TYPE_FLT64 = 4
397TYPE_UNS8 = 5
398TYPE_UNS16 = 6
399TYPE_UNS32 = 7
400TYPE_UNS64 = 8
401TYPE_ENUM = 9
402TYPE_BOOLEAN = 11
403TYPE_INT8 = 12
404TYPE_CHAR_PTR = 13
405TYPE_VOID_PTR = 14
406TYPE_VOID_PTR_PTR = 15
407TYPE_INT64 = 16
408TYPE_SMART_STREAM_TYPE = 17
409TYPE_SMART_STREAM_TYPE_PTR = 18
410TYPE_FLT32 = 19
411CLASS0 = 0
412CLASS2 = 2
413CLASS3 = 3
414PARAM_DD_INFO_LENGTH = 16777217
415PARAM_DD_VERSION = 100663298
416PARAM_DD_RETRIES = 100663299
417PARAM_DD_TIMEOUT = 100663300
418PARAM_DD_INFO = 218103813
419PARAM_ADC_OFFSET = 16908483
420PARAM_CHIP_NAME = 218235009
421PARAM_SYSTEM_NAME = 218235010
422PARAM_VENDOR_NAME = 218235011
423PARAM_PRODUCT_NAME = 218235012
424PARAM_CAMERA_PART_NUMBER = 218235013
425PARAM_COOLING_MODE = 151126230
426PARAM_PREAMP_DELAY = 100794870
427PARAM_COLOR_MODE = 151126520
428PARAM_MPP_CAPABLE = 151126240
429PARAM_PREAMP_OFF_CONTROL = 117572091
430PARAM_PREMASK = 100794421
431PARAM_PRESCAN = 100794423
432PARAM_POSTMASK = 100794422
433PARAM_POSTSCAN = 100794424
434PARAM_PIX_PAR_DIST = 100794868
435PARAM_PIX_PAR_SIZE = 100794431
436PARAM_PIX_SER_DIST = 100794869
437PARAM_PIX_SER_SIZE = 100794430
438PARAM_SUMMING_WELL = 184680953
439PARAM_FWELL_CAPACITY = 117572090
440PARAM_PAR_SIZE = 100794425
441PARAM_SER_SIZE = 100794426
442PARAM_ACCUM_CAPABLE = 184680986
443PARAM_FLASH_DWNLD_CAPABLE = 184680987
444PARAM_READOUT_TIME = 67240115
445PARAM_CLEAR_CYCLES = 100794465
446PARAM_CLEAR_MODE = 151126539
447PARAM_FRAME_CAPABLE = 184680957
448PARAM_PMODE = 151126540
449PARAM_TEMP = 16908813
450PARAM_TEMP_SETPOINT = 16908814
451PARAM_CAM_FW_VERSION = 100794900
452PARAM_HEAD_SER_NUM_ALPHA = 218235413
453PARAM_PCI_FW_VERSION = 100794902
454PARAM_FAN_SPEED_SETPOINT = 151126726
455PARAM_EXPOSURE_MODE = 151126551
456PARAM_EXPOSE_OUT_MODE = 151126576
457PARAM_BIT_DEPTH = 16908799
458PARAM_GAIN_INDEX = 16908800
459PARAM_SPDTAB_INDEX = 16908801
460PARAM_GAIN_NAME = 218235394
461PARAM_READOUT_PORT = 151126263
462PARAM_PIX_TIME = 100794884
463PARAM_SHTR_CLOSE_DELAY = 100794887
464PARAM_SHTR_OPEN_DELAY = 100794888
465PARAM_SHTR_OPEN_MODE = 151126537
466PARAM_SHTR_STATUS = 151126538
467PARAM_IO_ADDR = 100794895
468PARAM_IO_TYPE = 151126544
469PARAM_IO_DIRECTION = 151126545
470PARAM_IO_STATE = 67240466
471PARAM_IO_BITDEPTH = 100794899
472PARAM_GAIN_MULT_FACTOR = 100794905
473PARAM_GAIN_MULT_ENABLE = 184680989
474PARAM_PP_FEAT_NAME = 218235422
475PARAM_PP_INDEX = 16908831
476PARAM_ACTUAL_GAIN = 100794912
477PARAM_PP_PARAM_INDEX = 16908833
478PARAM_PP_PARAM_NAME = 218235426
479PARAM_PP_PARAM = 117572131
480PARAM_READ_NOISE = 100794916
481PARAM_PP_FEAT_ID = 100794917
482PARAM_PP_PARAM_ID = 100794918
483PARAM_SMART_STREAM_MODE_ENABLED = 184681148
484PARAM_SMART_STREAM_MODE = 100795069
485PARAM_SMART_STREAM_EXP_PARAMS = 235012798
486PARAM_SMART_STREAM_DLY_PARAMS = 235012799
487PARAM_EXP_TIME = 100859905
488PARAM_EXP_RES = 151191554
489PARAM_EXP_RES_INDEX = 100859908
490PARAM_EXPOSURE_TIME = 134414344
491PARAM_BOF_EOF_ENABLE = 151191557
492PARAM_BOF_EOF_COUNT = 117637126
493PARAM_BOF_EOF_CLR = 184745991
494PARAM_CIRC_BUFFER = 184746283
495PARAM_FRAME_BUFFER_SIZE = 134414636
496PARAM_BINNING_SER = 151191717
497PARAM_BINNING_PAR = 151191718
498PARAM_METADATA_ENABLED = 184746152
499PARAM_ROI_COUNT = 100860073
500PARAM_CENTROIDS_ENABLED = 184746154
501PARAM_CENTROIDS_RADIUS = 100860075
502PARAM_CENTROIDS_COUNT = 100860076
503PARAM_TRIGTAB_SIGNAL = 151191732
504PARAM_LAST_MUXED_SIGNAL = 84082869
505
506
507# === C structures ===
508# GUID for #FRAME_INFO structure.
509class PVCAM_FRAME_INFO_GUID(ctypes.Structure):
510 _fields_ = [
511 ("f1", uns32),
512 ("f2", uns16),
513 ("f3", uns16),
514 ("f4", uns8 * 8),
515 ]
516
517
518# Structure used to uniquely identify frames in the camera.
519class FRAME_INFO(ctypes.Structure):
520 _fields_ = [
521 ("FrameInfoGUID", PVCAM_FRAME_INFO_GUID),
522 ("hCam", int16),
523 ("FrameNr", int32),
524 ("TimeStamp", long64),
525 ("ReadoutTime", int32),
526 ("TimeStampBOF", long64),
527 ]
528
529
530class smart_stream_type(ctypes.Structure):
531 _fields_ = [
532 ("entries", uns16),
533 ("params", uns32),
534 ]
535
536
537class rgn_type(ctypes.Structure):
538 _fields_ = [
539 ("s1", uns16),
540 ("s2", uns16),
541 ("sbin", uns16),
542 ("p1", uns16),
543 ("p2", uns16),
544 ("pbin", uns16),
545 ]
546
547
548class io_struct(ctypes.Structure):
549 pass
550
551
552io_struct._fields_ = [
553 ("io_port", uns16),
554 ("io_type", uns32),
555 ("state", flt64),
556 ("next", ctypes.POINTER(io_struct)),
557]
558
559
560class io_list(ctypes.Structure):
561 _fields_ = [
562 ("pre_open", ctypes.POINTER(io_struct)),
563 ("post_open", ctypes.POINTER(io_struct)),
564 ("pre_flash", ctypes.POINTER(io_struct)),
565 ("post_flash", ctypes.POINTER(io_struct)),
566 ("pre_integrate", ctypes.POINTER(io_struct)),
567 ("post_integrate", ctypes.POINTER(io_struct)),
568 ("pre_readout", ctypes.POINTER(io_struct)),
569 ("post_readout", ctypes.POINTER(io_struct)),
570 ("pre_close", ctypes.POINTER(io_struct)),
571 ("post_close", ctypes.POINTER(io_struct)),
572 ]
573
574
575class active_camera_type(ctypes.Structure):
576 _fields_ = [
577 ("shutter_close_delay", uns16),
578 ("shutter_open_delay", uns16),
579 ("rows", uns16),
580 ("cols", uns16),
581 ("prescan", uns16),
582 ("postscan", uns16),
583 ("premask", uns16),
584 ("postmask", uns16),
585 ("preflash", uns16),
586 ("clear_count", uns16),
587 ("preamp_delay", uns16),
588 ("mpp_selectable", rs_bool),
589 ("frame_selectable", rs_bool),
590 ("do_clear", uns16),
591 ("open_shutter", uns16),
592 ("mpp_mode", rs_bool),
593 ("frame_transfer", rs_bool),
594 ("alt_mode", rs_bool),
595 ("exp_res", uns32),
596 ("io_hdr", ctypes.POINTER(io_list)),
597 ]
598
599
600class md_frame_header(ctypes.Structure):
601 _fields_ = [
602 ("signature", uns32),
603 ("version", uns8),
604 ("frameNr", uns32),
605 ("roiCount", uns16),
606 ("timestampBOF", uns32),
607 ("timestampEOF", uns32),
608 ("timestampResNs", uns32),
609 ("exposureTime", uns32),
610 ("exposureTimeResN", uns32),
611 ("roiTimestampResN", uns32),
612 ("bitDepth", uns8),
613 ("colorMask", uns8),
614 ("flags", uns8),
615 ("extendedMdSize", uns16),
616 ("_reserved", uns8 * 8),
617 ]
618
619
620class md_frame_roi_header(ctypes.Structure):
621 _fields_ = [
622 ("roiNr", uns16),
623 ("timestampBOR", uns32),
624 ("timestampEOR", uns32),
625 ("roi", rgn_type),
626 ("flags", uns8),
627 ("extendedMdSize", uns16),
628 ("_reserved", uns8 * 7),
629 ]
630
631
632class md_ext_item_info(ctypes.Structure):
633 _fields_ = [
634 ("tag", uns16),
635 ("size", uns16),
636 ("name", ctypes.c_char_p),
637 ]
638
639
640class md_ext_item(ctypes.Structure):
641 _fields_ = [
642 ("tagInfo", ctypes.POINTER(md_ext_item_info)), #
643 ("value", ctypes.c_void_p),
644 ]
645
646
647class md_ext_item_collection(ctypes.Structure):
648 _fields_ = [
649 ("list", md_ext_item * PL_MD_EXT_TAGS_MAX_SUPPORTED),
650 ("map", ctypes.POINTER(md_ext_item) * PL_MD_EXT_TAGS_MAX_SUPPORTED),
651 ("count", uns16),
652 ]
653
654
655class md_frame_roi(ctypes.Structure):
656 _fields_ = [
657 ("header", ctypes.POINTER(md_frame_roi_header)),
658 ("data", ctypes.c_void_p),
659 ("dataSize", uns32),
660 ("extMdData", ctypes.c_void_p),
661 ("extMdDataSize", uns16),
662 ]
663
664
665class md_frame(ctypes.Structure):
666 _fields_ = [
667 ("header", ctypes.POINTER(md_frame_header)),
668 ("extMdData", ctypes.c_void_p),
669 ("extMdDataSize", uns16),
670 ("impliedRoi", rgn_type),
671 ("roiArray", ctypes.POINTER(md_frame_roi)),
672 ("roiCapacity", uns16),
673 ("roiCount", uns16),
674 ]
675
676
677if os.name in ("nt", "ce"):
678 if platform.architecture()[0] == "32bit":
679 _lib = ctypes.WinDLL("pvcam32")
680 else:
681 _lib = ctypes.WinDLL("pvcam64")
682else:
683 _lib = ctypes.CDLL("pvcam.so")
684
685### Functions ###
686STRING = ctypes.c_char_p
687
688# classes so that we do some magic and automatically add byrefs etc ... can classify outputs
689# (Nicked from PYME's Ixon wrapper.)
690class _meta:
691 pass
692
693
694class OUTPUT(_meta):
695 def __init__(self, val):
696 self.type = val
697 self.val = ctypes.POINTER(val)
698
699 def get_var(self, buf_len=0):
700 if self.type in [STRING, ctypes.c_void_p] and buf_len > 0:
701 v = ctypes.create_string_buffer(buf_len)
702 ref = ctypes.cast(ctypes.pointer(v), self.val)
703 else:
704 v = self.type()
705 ref = ctypes.byref(v)
706 return v, ref
707
708
710 def __init__(self):
711 self.valval = STRING
712
713 def get_var(self, buf_len):
714 v = ctypes.create_string_buffer(buf_len)
715 return v, v
716
717
718OUTSTRING = _OUTSTRING()
719
720
721def stripMeta(val):
722 """Strip meta info from OUTPUT and OUTSTRING instances."""
723 if isinstance(val, _meta):
724 return val.val
725 else:
726 return val
727
728
729# Function type for callbacks.
730CALLBACK = ctypes.CFUNCTYPE(ctypes.c_void_p)
731
732
734 """Expose a DLL function to python.
735
736 (Again, largely nicked from PYME.)"""
737
738 def __init__(self, name, args=[], argnames=[], buf_len=-1, lib=_lib):
739 self.f = getattr(lib, name)
740 self.f.restype = rs_bool
741 self.f.argtypes = [stripMeta(a) for a in args]
742
743 self.fargs = args
744 self.fargnames = argnames
745 self.name = name
746
747 self.inp = [not isinstance(a, OUTPUT) for a in args]
748 self.in_args = [a for a in args if not isinstance(a, OUTPUT)]
749 self.out_args = [a for a in args if isinstance(a, OUTPUT)]
750
751 self.buf_len = buf_len
752
753 docstring = name + "\n\nArguments:\n===========\n"
754 for i in range(len(args)):
755 an = ""
756 if i < len(argnames):
757 an = argnames[i]
758 docstring += "\t%s\t%s\n" % (args[i], an)
759
760 self.f.__doc__ = docstring
761
762 def __call__(self, *args, **kwargs):
763 ars = []
764 i = 0
765 ret = []
766 # pl_get_param buffer length depends on the parameter being fetched, so
767 # use kwargs to pass buffer length.
768 if "buf_len" in kwargs:
769 bs = kwargs["buf_len"]
770 elif self.name == "pl_get_enum_param":
771 # last argument is buffer length
772 bs = args[-1]
773 elif self.buf_len >= 0:
774 bs = self.buf_len
775 else:
776 bs = 256
777 # May have been passed a ctype; if so, fetch its value.
778 if isinstance(bs, ctypes._SimpleCData):
779 bs = bs.value
780
781 for j in range(len(self.inp)):
782 if self.inp[j]: # an input
783 if self.f.argtypes[j] is CALLBACK and not isinstance(
784 args[i], CALLBACK
785 ):
786 ars.append(CALLBACK(args[i]))
787 else:
788 ars.append(args[i])
789 i += 1
790 else: # an output
791 r, ar = self.fargs[j].get_var(bs)
792 ars.append(ar)
793 ret.append(r)
794 # print r, r._type_
795
796 # print (self.name, ars)
797 res = self.f(*ars)
798 # print res
799
800 if res == False:
801 err_code = _lib.pl_error_code()
802 err_msg = ctypes.create_string_buffer(ERROR_MSG_LEN)
803 _lib.pl_error_message(err_code, err_msg)
805 "pvcam error %d: %s" % (err_code, err_msg.value)
806 )
807
808 if len(ret) == 0:
809 return None
810 if len(ret) == 1:
811 return ret[0]
812 else:
813 return ret
814
815
816def _status():
817 """Fetch the PVCAM DLL status."""
818 err_code = _lib.pl_error_code()
819 err_msg = ctypes.create_string_buffer(ERROR_MSG_LEN)
820 _lib.pl_error_message(err_code, err_msg)
821
822
823def dllFunc(name, args=[], argnames=[], buf_len=0):
824 """Register a function using dllFunction."""
825 f = dllFunction(name, args, argnames, buf_len=buf_len)
826 globals()[name[2:]] = f
827
828
829"""DLL function imports."""
830# Class 0 functions - library
831dllFunc("pl_pvcam_get_ver", [OUTPUT(uns16)], ["version"])
832dllFunc("pl_pvcam_init")
833dllFunc("pl_pvcam_uninit")
834# Class 0 functions - camera
835dllFunc("pl_cam_close", [int16], ["hcam"])
836dllFunc(
837 "pl_cam_get_name",
838 [int16, OUTSTRING],
839 ["can_num", "cam_name"],
840 buf_len=CAM_NAME_LEN,
841)
842dllFunc(
843 "pl_cam_get_total",
844 [
845 OUTPUT(int16),
846 ],
847 [
848 "total_cams",
849 ],
850)
851dllFunc(
852 "pl_cam_open",
853 [STRING, OUTPUT(int16), int16],
854 ["cam_name", "hcam", "o_mode"],
855)
856dllFunc(
857 "pl_cam_register_callback",
858 [int16, int32, CALLBACK],
859 ["hcam", "event", "Callback"],
860)
861dllFunc(
862 "pl_cam_register_callback_ex",
863 [int16, int32, CALLBACK, ctypes.c_void_p],
864 ["hcam", "event", "Callback", "Context"],
865)
866dllFunc(
867 "pl_cam_register_callback_ex2",
868 [int16, int32, CALLBACK],
869 ["hcam", "event", "Callback"],
870)
871dllFunc(
872 "pl_cam_register_callback_ex3",
873 [int16, int32, CALLBACK, ctypes.c_void_p],
874 ["hcam", "event", "Callback", "Context"],
875)
876dllFunc(
877 "pl_cam_deregister_callback", [int16, ctypes.c_void_p], ["hcam", "event"]
878)
879# Class 1 functions - error handling. Handled in dllFunction.
880# Class 2 functions - configuration/setup.
881dllFunc(
882 "pl_get_param",
883 [int16, uns32, int16, OUTPUT(ctypes.c_void_p)],
884 ["hcam", "param_id", "param_attrib", "param_value"],
885)
886dllFunc(
887 "pl_set_param",
888 [int16, uns32, ctypes.c_void_p],
889 ["hcam", "param_id", "param_value"],
890)
891dllFunc(
892 "pl_get_enum_param",
893 [int16, uns32, uns32, OUTPUT(int32), OUTSTRING, uns32],
894 ["hcam", "param_id", "index", "value", "desc", "length"],
895)
896dllFunc(
897 "pl_enum_str_length",
898 [int16, uns32, uns32, OUTPUT(uns32)],
899 ["hcam", "param_id", "index", "length"],
900)
901dllFunc(
902 "pl_pp_reset",
903 [
904 int16,
905 ],
906 ["hcam"],
907)
908dllFunc(
909 "pl_create_smart_stream_struct",
910 [OUTPUT(smart_stream_type), uns16],
911 ["pSmtStruct", "entries"],
912)
913dllFunc(
914 "pl_release_smart_stream_struct",
915 [
916 ctypes.POINTER(smart_stream_type),
917 ],
918 [
919 "pSmtStruct",
920 ],
921)
922dllFunc(
923 "pl_create_frame_info_struct",
924 [
925 OUTPUT(FRAME_INFO),
926 ],
927 ["pNewFrameInfo"],
928)
929dllFunc(
930 "pl_release_frame_info_struct",
931 [
932 ctypes.POINTER(FRAME_INFO),
933 ],
934 [
935 "pFrameInfoToDel",
936 ],
937)
938dllFunc("pl_exp_abort", [int16, int16], ["hcam", "cam_state"])
939dllFunc(
940 "pl_exp_setup_seq",
941 [
942 int16,
943 uns16,
944 uns16,
945 ctypes.POINTER(rgn_type),
946 int16,
947 uns32,
948 OUTPUT(uns32),
949 ],
950 [
951 "hcam",
952 "exp_total",
953 "rgn_total",
954 "rgn_array",
955 "exp_mode",
956 "exposure_time",
957 "exp_bytes",
958 ],
959)
960dllFunc("pl_exp_start_seq", [int16, ctypes.c_void_p], ["hcam", "pixel_stream"])
961dllFunc(
962 "pl_exp_setup_cont",
963 [
964 int16,
965 uns16,
966 ctypes.POINTER(rgn_type),
967 int16,
968 uns32,
969 OUTPUT(uns32),
970 int16,
971 ],
972 [
973 "hcam",
974 "rgn_total",
975 "rgn_array",
976 "exp_mode",
977 "exposure_time",
978 "exp_bytes",
979 "buffer_mode",
980 ],
981)
982dllFunc(
983 "pl_exp_start_cont",
984 [int16, ctypes.c_void_p, uns32],
985 ["hcam", "pixel_stream", "size"],
986)
987dllFunc(
988 "pl_exp_check_status",
989 [int16, OUTPUT(int16), OUTPUT(uns32)],
990 ["hcam", "status", "bytes_arrived"],
991)
992dllFunc(
993 "pl_exp_check_cont_status",
994 [int16, OUTPUT(int16), OUTPUT(uns32), OUTPUT(uns32)],
995 ["hcam", "status", "bytes_arrived", "buffer_cnt"],
996)
997dllFunc(
998 "pl_exp_check_cont_status_ex",
999 [
1000 int16,
1001 OUTPUT(int16),
1002 OUTPUT(uns32),
1003 OUTPUT(uns32),
1004 ctypes.POINTER(FRAME_INFO),
1005 ],
1006 ["hcam", "status", "byte_cnt", "buffer_cnt", "pFrameInfo"],
1007)
1008dllFunc(
1009 "pl_exp_get_latest_frame",
1010 [int16, OUTPUT(ctypes.c_void_p)],
1011 ["hcam", "frame"],
1012)
1013dllFunc(
1014 "pl_exp_get_latest_frame_ex",
1015 [int16, OUTPUT(ctypes.c_void_p), ctypes.POINTER(FRAME_INFO)],
1016 ["hcam", "frame", "pFrameInfo"],
1017)
1018dllFunc(
1019 "pl_exp_get_oldest_frame",
1020 [int16, OUTPUT(ctypes.c_void_p)],
1021 ["hcam", "frame"],
1022)
1023dllFunc(
1024 "pl_exp_get_oldest_frame_ex",
1025 [int16, OUTPUT(ctypes.c_void_p), ctypes.POINTER(FRAME_INFO)],
1026 ["hcam", "frame", "pFrameInfo"],
1027)
1028dllFunc("pl_exp_unlock_oldest_frame", [int16], ["hcam"])
1029dllFunc("pl_exp_stop_cont", [int16, int16], ["hcam", "cam_state"])
1030dllFunc("pl_exp_abort", [int16, int16], ["hcam", "cam_state"])
1031dllFunc(
1032 "pl_exp_finish_seq", [int16, ctypes.c_void_p], ["hcam", "pixel_stream"]
1033)
1034
1035
1036# Map ATTR_ enums to the return type for that ATTR.
1037_attr_map = {
1038 ATTR_ACCESS: uns16,
1039 ATTR_AVAIL: rs_bool,
1040 ATTR_COUNT: uns32,
1041 ATTR_CURRENT: None,
1042 ATTR_DEFAULT: None,
1043 ATTR_INCREMENT: None,
1044 ATTR_MAX: None,
1045 ATTR_MIN: None,
1046 ATTR_TYPE: uns16,
1047}
1048
1049# Map TYPE enums to their type.
1050_typemap = {
1051 TYPE_INT16: int16,
1052 TYPE_INT32: int32,
1053 TYPE_FLT64: flt64,
1054 TYPE_UNS8: uns8,
1055 TYPE_UNS16: uns16,
1056 TYPE_UNS32: uns32,
1057 TYPE_UNS64: ulong64,
1058 TYPE_ENUM: int32, # from SDK documentation
1059 TYPE_BOOLEAN: rs_bool,
1060 TYPE_INT8: int8,
1061 TYPE_CHAR_PTR: ctypes.c_char_p,
1062 TYPE_VOID_PTR: ctypes.c_void_p,
1063 TYPE_VOID_PTR_PTR: ctypes.POINTER(ctypes.c_void_p),
1064 TYPE_INT64: long64,
1065 TYPE_SMART_STREAM_TYPE: smart_stream_type,
1066 TYPE_SMART_STREAM_TYPE_PTR: ctypes.POINTER(smart_stream_type),
1067 TYPE_FLT32: flt32,
1068}
1069
1070
1071# Map TYPE enums to the appropriate setting dtype.
1072_dtypemap = {
1073 TYPE_INT16: "int",
1074 TYPE_INT32: "int",
1075 TYPE_FLT64: "float",
1076 TYPE_UNS8: "int",
1077 TYPE_UNS16: "int",
1078 TYPE_UNS32: "int",
1079 TYPE_UNS64: "int",
1080 TYPE_ENUM: "enum",
1081 TYPE_BOOLEAN: "bool",
1082 TYPE_INT8: "int",
1083 TYPE_CHAR_PTR: "str",
1084 TYPE_VOID_PTR: None,
1085 TYPE_VOID_PTR_PTR: None,
1086 TYPE_INT64: "int",
1087 TYPE_SMART_STREAM_TYPE: None,
1088 TYPE_SMART_STREAM_TYPE_PTR: None,
1089 TYPE_FLT32: "float",
1090}
1091
1092# Mapping of param ids to maximum string lengths.
1093# PARAM_DD_INFO is a variable length string, and its length can be found by
1094# querying PARAM_DD_INFO_LEN. However, querying PARAM_DD_INFO frequently causes
1095# a general protection fault in the DLL, regardless of buffer length.
1096_length_map = {
1097 PARAM_DD_INFO: PARAM_DD_INFO_LENGTH,
1098 PARAM_CHIP_NAME: CCD_NAME_LEN,
1099 PARAM_SYSTEM_NAME: MAX_SYSTEM_NAME_LEN,
1100 PARAM_VENDOR_NAME: MAX_VENDOR_NAME_LEN,
1101 PARAM_PRODUCT_NAME: MAX_PRODUCT_NAME_LEN,
1102 PARAM_CAMERA_PART_NUMBER: MAX_CAM_PART_NUM_LEN,
1103 PARAM_GAIN_NAME: MAX_GAIN_NAME_LEN,
1104 PARAM_HEAD_SER_NUM_ALPHA: MAX_ALPHA_SER_NUM_LEN,
1105 PARAM_PP_FEAT_NAME: MAX_PP_NAME_LEN,
1106 PARAM_PP_PARAM_NAME: MAX_PP_NAME_LEN,
1107}
1108
1109# map PARAM enums to the parameter name
1110_param_to_name = {
1111 globals()[param]: param
1112 for param in globals()
1113 if (param.startswith("PARAM_") and param != "PARAM_NAME_LEN")
1114}
1115
1116
1117def get_param_type(param_id):
1118 """Return parameter type code (for C/DLL) for param_id."""
1119 # Parameter types are encoded in the 4th MSB of the param_id.
1120 return _typemap[param_id >> 24 & 255]
1121
1122
1123def get_param_dtype(param_id):
1124 """Return parameter dtype (for microscope settings) for param_id."""
1125 # Parameter types are encoded in the 4th MSB of the param_id.
1126 return _dtypemap[param_id >> 24 & 255]
1127
1128
1129# Map status codes to strings.
1130STATUS_STRINGS = {
1131 READOUT_NOT_ACTIVE: "READOUT_NOT_ACTIVE",
1132 EXPOSURE_IN_PROGRESS: "EXPOSURE_IN_PROGRESS",
1133 READOUT_IN_PROGRESS: "READOUT_IN_PROGRESS",
1134 READOUT_COMPLETE: "READOUT_COMPLETE",
1135 READOUT_FAILED: "READOUT_FAILED",
1136 FRAME_AVAILABLE: "FRAME_AVAILABLE",
1137}
1138
1139
1140# === Python classes ===
1141# Trigger modes.
1143 """A microscope trigger mode using PVCAM PMODES."""
1144
1145 def __init__(self, label, pv_mode):
1146 self.label = label
1147 self.pv_mode = pv_mode
1148
1149 def __repr__(self):
1150 return "<%s: '%s'>" % (type(self).__name__, self.label)
1151
1152
1153# Enumerate trigger types.
1154(
1155 TRIG_SOFT,
1156 TRIG_TIMED,
1157 TRIG_VARIABLE,
1158 TRIG_FIRST,
1159 TRIG_STROBED,
1160 TRIG_BULB,
1161) = range(6)
1162
1163# Trigger mode definitions.
1164TRIGGER_MODES = {
1165 TRIG_SOFT: TriggerMode("software", TIMED_MODE),
1166 TRIG_TIMED: TriggerMode("timed", TIMED_MODE),
1167 TRIG_VARIABLE: TriggerMode("variable timed", VARIABLE_TIMED_MODE),
1168 TRIG_FIRST: TriggerMode("trig. first", TRIGGER_FIRST_MODE),
1169 TRIG_STROBED: TriggerMode("strobed", STROBED_MODE),
1170 TRIG_BULB: TriggerMode("bulb", BULB_MODE),
1171}
1172
1173PV_MODE_TO_TRIGGER = {
1174 TRIG_SOFT: (microscope.TriggerType.SOFTWARE, microscope.TriggerMode.ONCE),
1175 # Microscope and PVCam use mode strobe for very different things,
1176 # check with the PVCam manual carefully. PVCam's STROBED_MODE
1177 # means that one external trigger starts *each* exposure in a
1178 # sequence, which maps to Microscope trigger mode ONCE. PVCam's
1179 # TRIGGER_FIRST_MODE means that one external trigger signals the
1180 # start of a sequence.
1181 TRIG_FIRST: (
1182 microscope.TriggerType.RISING_EDGE,
1183 microscope.TriggerMode.START,
1184 ),
1185 TRIG_STROBED: (
1186 microscope.TriggerType.RISING_EDGE,
1187 microscope.TriggerMode.ONCE,
1188 ),
1189 TRIG_BULB: (
1190 microscope.TriggerType.RISING_EDGE,
1191 microscope.TriggerMode.BULB,
1192 ),
1193}
1194
1195
1196TRIGGER_TO_PV_MODE = {v: k for k, v in PV_MODE_TO_TRIGGER.items()}
1197
1198
1200 """A wrapper around PVCAM parameters."""
1201
1202 @staticmethod
1203 def factory(camera, param_id):
1204 """Create a PVParam or appropriate subclass"""
1205 # A mapping of pv parameters types to python types.
1206 # None means unsupported.
1207 # Parameters omitted from the mapping will default to PVParam.
1208 __types__ = {
1209 TYPE_SMART_STREAM_TYPE: None,
1210 TYPE_SMART_STREAM_TYPE_PTR: None,
1211 TYPE_VOID_PTR: None,
1212 TYPE_VOID_PTR_PTR: None,
1213 TYPE_ENUM: PVEnumParam,
1214 TYPE_CHAR_PTR: PVStringParam,
1215 }
1216 # Determine the appropiate type from its id.
1217 pvtype = __types__.get(param_id >> 24 & 255, PVParam)
1218 if pvtype is None:
1220 "Parameter %s not supported" % _param_to_name[param_id]
1221 )
1222 return pvtype(camera, param_id)
1223
1224 def __init__(self, camera, param_id):
1225 # Use a weakref back to the camera to avoid circular dependency.
1226 self.cam = weakref.proxy(camera)
1227 self.param_id = param_id
1228 self.name = _param_to_name[param_id]
1229 self._pvtype = param_id >> 24 & 255
1230 if self.name == "PARAM_READOUT_TIME":
1231 # Bugged. Here is what the SDK says: "The parameter type is
1232 # incorrectly defined. The actual type is TYPE_UNS32."
1233 self._pvtype = TYPE_UNS32
1234 self.dtype = _dtypemap[self._pvtype]
1235 self._ctype = _typemap[self._pvtype]
1236 self.__cache = {}
1237
1238 def set_value(self, new_value):
1239 """Set a parameter value.
1240
1241 Subclasses should do whatever processing they need on new_value,
1242 then call super().set_value(new_value)"""
1243 try:
1244 ref = ctypes.byref(new_value)
1245 except TypeError:
1246 # Need to convert python type to ctype first.
1247 ref = ctypes.byref(self._ctype(new_value))
1248 _set_param(self.cam.handle, self.param_id, ref)
1249 # Read back the value to update cache.
1250 self._query(force_query=True)
1251
1252 def _query(self, what=ATTR_CURRENT, force_query=False):
1253 """Query the DLL for an attribute for this parameter.
1254
1255 This returns pythonic types, not ctypes."""
1256 err = None
1257 key = (self, what) # key for cache
1258 if self.cam._acquiring and not force_query:
1259 return self.__cache.get(key, None)
1260 if what == ATTR_AVAIL:
1261 return self.available
1262 elif not self.available:
1264 "Parameter %s is not available" % self.name
1265 )
1266 rtype = _attr_map[what] # return type
1267 if not rtype:
1268 rtype = _get_param(self.cam.handle, self.param_id, ATTR_TYPE)
1269 if rtype.value == TYPE_CHAR_PTR:
1270 buf_len = _length_map[self.param_id]
1271 if not buf_len:
1273 "pvcam: parameter %s not supported in python." % self.name
1274 )
1275 try:
1276 result = _get_param(
1277 self.cam.handle, self.param_id, what, buf_len=buf_len
1278 )
1279 except Exception as e:
1280 err = e
1281 else:
1282 result = result.value
1283 else:
1284 try:
1285 result = _get_param(self.cam.handle, self.param_id, what)
1286 except Exception as e:
1287 err = e
1288 else:
1289 result = ctypes.POINTER(self._ctype)(result).contents.value
1290 # Test on err.args prevents indexing into empty tuple.
1291 if err and err.args and err.args[0].startswith("pvcam error 49"):
1292 _logger.warn(
1293 "Parameter %s not available due to camera state.", self.name
1294 )
1295 result = None
1296 elif err:
1297 raise e
1298 else:
1299 self.__cache[key] = result
1300 return result
1301
1302 @property
1303 def access(self):
1304 """Return parameter access attribute."""
1305 return int(
1306 _get_param(self.cam.handle, self.param_id, ATTR_ACCESS).value
1307 )
1308
1309 @property
1310 def available(self):
1311 """Return whether or not parameter is available on hardware."""
1312 return bool(
1313 _get_param(self.cam.handle, self.param_id, ATTR_AVAIL).value
1314 )
1315
1316 @property
1317 def count(self):
1318 """Return count of parameter enum entries."""
1319 return int(
1320 _get_param(self.cam.handle, self.param_id, ATTR_COUNT).value
1321 )
1322
1323 @property
1324 def values(self):
1325 """Get parameter min and max values.
1326
1327 Subclasses for strings and enum override this."""
1328 return (self._query(ATTR_MIN), self._query(ATTR_MAX))
1329
1330 @property
1331 def current(self):
1332 """Return the current (or cached) parameter value.
1333
1334 Subclasses should override this for more complex data types."""
1335 return self._query()
1336
1337
1339 """PVParam subclass for enums"""
1340
1341 def set_value(self, new_value):
1342 """Set an enum parameter value."""
1343 # We may be passed a value, a description string, or a tuple of
1344 # (value, string).
1345 values, descriptions = list(zip(*self.valuesvalues.items()))
1346 if hasattr(new_value, "__iter__"):
1347 desc = str(new_value[1])
1348 elif isinstance(new_value, str):
1349 desc = str(new_value)
1350 else:
1351 desc = None
1352 # If we have a description, rely on that, as this avoids any confusion
1353 # of index and value.
1354 if desc and desc in descriptions:
1355 new_index = descriptions.index(desc)
1356 new_value = values[new_index]
1357 elif desc:
1358 raise Exception(
1359 "Could not find description '%s' for enum %s."
1360 % (desc, self.name)
1361 )
1362 super().set_value(new_value)
1363
1364 @property
1365 def current(self):
1366 """Return the current (or cached) enum parameter value."""
1367 # c_void_p(0) is None, so replace with 0
1368 return int(self._query() or 0)
1369
1370 @property
1371 def values(self):
1372 """Get allowable enum values"""
1373 values = {}
1374 for i in range(self.count):
1375 length = _enum_str_length(self.cam.handle, self.param_id, i)
1376 value, desc = _get_enum_param(
1377 self.cam.handle, self.param_id, i, length
1378 )
1379 values[value.value] = desc.value.decode()
1380 return values
1381
1382
1384 """PVParam subclass for strings"""
1385
1386 def set_value(self, new_value):
1387 """Set a string parameter value"""
1388 if hasattr(new_value, "encode"):
1389 new_value = new_value.encode()
1390 super().set_value(new_value)
1391
1392 @property
1393 def current(self):
1394 """Return the current (or cached) string parameter value."""
1395 return self._query().decode()
1396
1397 @property
1398 def values(self):
1399 """Get allowable string length."""
1400 values = _length_map[self.param_id] or 0
1401 return values
1402
1403
1407):
1408 """Implements the CameraDevice interface for the pvcam library."""
1409
1410 # Keep track of open cameras.
1411 open_cameras = []
1412
1413 def __init__(self, index=0, **kwargs):
1414 super().__init__(index=index, **kwargs)
1415 # Camera name in DLL.
1416 self._pv_name = None
1417 # Camera handle.
1418 self.handle = None
1419 # Sensor shape.
1420 self.shape = (None, None)
1421 # Region of interest.
1422 self.roi = (None, None, None, None)
1423 # Binning setting.
1424 self.binning = microscope.Binning(1, 1)
1425 self._trigger = TRIG_STROBED
1426 self.exposure_time = 0.001 # in seconds
1427 # Cycle time
1428 self.cycle_time = self.exposure_time
1429 # Data buffer.
1430 self._buffer = None
1431 # This devices PVCAM parameters.
1432 self._params = {}
1433 # Circular buffer length.
1434 self._circ_buffer_length = 10
1435
1436 # Add common settings.
1437 self.add_setting(
1438 "exposure time",
1439 "float",
1440 lambda: self.exposure_time,
1442 lambda: (1e-6, 1),
1443 )
1444 self.add_setting(
1445 "trigger mode",
1446 "enum",
1447 lambda: self._trigger,
1448 lambda value: setattr(self, "_trigger", value),
1449 {k: v.label for k, v in TRIGGER_MODES.items()},
1450 )
1451 self.add_setting(
1452 "circular buffer length",
1453 "int",
1454 lambda: self._circ_buffer_length,
1455 lambda value: setattr(self, "_circ_buffer_length", value),
1456 (2, 100),
1457 )
1458
1460
1461 @property
1462 def _region(self):
1463 """Return a rgn_type for current roi and binning settings."""
1464 return rgn_type(
1465 self.roi.left,
1466 self.roi.left + self.roi.width - 1,
1467 self.binning.h,
1468 self.roi.top,
1469 self.roi.top + self.roi.height - 1,
1470 self.binning.v,
1471 )
1472
1473 """Private methods, called here and within super classes."""
1474
1475 def _fetch_data(self):
1476 """Fetch data - for use in fetch_loop."""
1477 # Not used: images fetched using callback.
1478 return None
1479
1480 def _do_enable(self):
1481 """Enable the camera hardware and make ready to respond to triggers.
1482
1483 Return True if successful, False if not."""
1484 # Set exposure time resolution on camera and determine t_exp, the
1485 # integer value used to set exposure time on the hardware later.
1486 if self.exposure_time < 1e-3:
1487 self._params[PARAM_EXP_RES].set_value(EXP_RES_ONE_MICROSEC)
1488 t_exp = int(self.exposure_time * 1e6)
1489 else:
1490 self._params[PARAM_EXP_RES].set_value(EXP_RES_ONE_MILLISEC)
1491 t_exp = int(self.exposure_time * 1e3)
1492 # Determine the data type of the buffer
1493 # Kinetix has an 8 bit mode, may need more options for colour
1494 # cameras.
1495 buffer_dtype = "uint16"
1496 if self._params[PARAM_BIT_DEPTH].current == 8:
1497 buffer_dtype = "uint8"
1498 # Configure camera, allocate buffer, and register callback.
1499 if self._trigger == TRIG_SOFT:
1500 # Software triggering for single frames.
1501 # Set up callback.
1503
1504 def cb():
1505 """Soft trigger mode end-of-frame callback."""
1506 timestamp = time.time()
1507 frame = self._buffer.copy()
1508 _logger.debug("Fetched single frame.")
1509 _exp_finish_seq(self.handle, CCS_CLEAR)
1510 self._put(frame, timestamp)
1511 return
1512
1513 # Need to keep a reference to the callback.
1514 self._eof_callback = CALLBACK(cb)
1515 _cam_register_callback(
1516 self.handle, PL_CALLBACK_EOF, self._eof_callback
1517 )
1518 nbytes = _exp_setup_seq(
1519 self.handle,
1520 1,
1521 1, # cam, num epxosures, num regions
1522 self._region,
1523 TRIGGER_MODES[self._trigger].pv_mode,
1524 t_exp,
1525 )
1526 buffer_shape = (
1527 self.roi.height // self.binning.v,
1528 self.roi.width // self.binning.h,
1529 )
1530 self._buffer = np.require(
1531 np.empty(buffer_shape, dtype=buffer_dtype),
1532 requirements=["C_CONTIGUOUS", "ALIGNED", "OWNDATA"],
1533 )
1534 else:
1535 # Use a circular buffer.
1537
1538 # Determine the data type of the frame
1539 frame_type = uns16
1540 if buffer_dtype == "uint8":
1541 frame_type = uns8
1542
1543 def cb():
1544 """Circular buffer mode end-of-frame callback."""
1545 timestamp = time.time()
1546 frame_p = ctypes.cast(
1547 _exp_get_latest_frame(self.handle),
1548 ctypes.POINTER(frame_type),
1549 )
1550 frame = np.ctypeslib.as_array(
1551 frame_p, (self.roi[2], self.roi[3])
1552 ).copy()
1553 _logger.debug("Fetched frame from circular buffer.")
1554 self._put(frame, timestamp)
1555 return
1556
1557 # Need to keep a reference to the callback.
1558 self._eof_callback = CALLBACK(cb)
1559 _cam_register_callback(
1560 self.handle, PL_CALLBACK_EOF, self._eof_callback
1561 )
1562 buffer_shape = (
1564 self.roi.height // self.binning.v,
1565 self.roi.width // self.binning.h,
1566 )
1567 self._buffer = np.require(
1568 np.empty(buffer_shape, dtype=buffer_dtype),
1569 requirements=["C_CONTIGUOUS", "ALIGNED", "OWNDATA"],
1570 )
1571 nbytes = _exp_setup_cont(
1572 self.handle,
1573 1,
1574 self._region,
1575 TRIGGER_MODES[self._trigger].pv_mode,
1576 t_exp,
1577 CIRC_OVERWRITE,
1578 ).value
1579
1580 # Read back exposure time.
1581 t_readback = self._params[PARAM_EXPOSURE_TIME].current
1582 t_resolution = self._params[PARAM_EXP_RES].current
1583 multipliers = {
1584 EXP_RES_ONE_SEC: 1.0,
1585 EXP_RES_ONE_MILLISEC: 1e-3,
1586 EXP_RES_ONE_MICROSEC: 1e-6,
1587 }
1588 if isinstance(t_resolution, tuple):
1589 self.exposure_time = t_readback * multipliers[t_resolution[0]]
1590 else:
1591 self.exposure_time = t_readback * multipliers[t_resolution]
1592 # Update cycle time. Exposure time in seconds; readout time in microseconds.
1593 self.cycle_time = (
1594 self.exposure_time
1595 + 1e-6 * self._params[PARAM_READOUT_TIME].current
1596 )
1597 # Set up exposure time for VARIABLE_TIMED_MODE, as according to documentation.
1598 # It doesn't seem to work.
1599 if self._trigger == TRIG_VARIABLE:
1600 self._params[PARAM_EXP_TIME].set_value(t_exp)
1601 # If using real triggering, start triggered acquisition.
1602 # (Software triggering will start acquisition in soft_trigger().)
1603 if self._trigger != TRIG_SOFT:
1604 _exp_start_cont(
1605 self.handle,
1606 self._buffer.ctypes.data_as(ctypes.c_void_p),
1607 self._buffer.nbytes,
1608 )
1609 # Done.
1610 self._acquiring_acquiring = True
1611 return self._acquiring_acquiring
1612
1613 def _do_disable(self):
1614 """Disable the hardware for a short period of inactivity."""
1615 self.abortabort()
1616 _cam_deregister_callback(self.handle, PL_CALLBACK_EOF)
1617
1618 def _do_shutdown(self) -> None:
1619 """Disable the hardware for a prolonged period of inactivity."""
1620 self.abortabort()
1621 _cam_close(self.handle)
1622 PVCamera.open_cameras.remove(self.handle)
1623 if not PVCamera.open_cameras:
1624 _logger.info("No more open cameras - calling _pvcam_uninit.")
1625 _pvcam_uninit()
1626
1627 """Private shape-related methods. These methods do not need to account
1628 for camera orientation or transforms due to readout mode, as that
1629 is handled in the parent class."""
1630
1631 def _get_sensor_shape(self):
1632 """Return the sensor shape (width, height)."""
1633 return self.shape
1634
1635 def _get_binning(self):
1636 """Return the current binning (horizontal, vertical)."""
1637 return self.binning
1638
1639 @microscope.abc.keep_acquiring
1640 def _set_binning(self, binning):
1641 """Set binning to (h, v)."""
1642 # The keep_acquiring decorator will cause recreation of buffers.
1643 self.binning = microscope.Binning(binning.h, binning.v)
1644
1645 def _get_roi(self):
1646 """Return the current ROI (left, top, width, height)."""
1647 return self.roi
1648
1649 @microscope.abc.keep_acquiring
1650 def _set_roi(self, roi):
1651 """Set the ROI to (left, tip, width, height)."""
1652 right = roi.left + roi.width
1653 bottom = roi.top + roi.height
1654 if (right, bottom) > self.shape:
1655 raise ValueError("ROI exceeds sensor area.")
1656 self.roi = roi
1657
1658 """Public methods, callable from client."""
1659
1660 def get_id(self):
1661 """Get hardware's unique identifier."""
1662 return self._params[PARAM_HEAD_SER_NUM_ALPHA].current
1663
1664 def abort(self):
1665 """Abort acquisition.
1666
1667 This should put the camera into a state in which settings can
1668 be modified."""
1669 if self._trigger == TRIG_SOFT:
1670 _exp_finish_seq(self.handle, CCS_CLEAR)
1671 else:
1672 _exp_stop_cont(self.handle, CCS_CLEAR)
1673 _exp_abort(self.handle, CCS_HALT)
1674 self._acquiring_acquiring = False
1675
1676 def initialize(self):
1677 """Initialise the camera."""
1678 # Init the DLL if necessary.
1679 if not PVCamera.open_cameras:
1680 try:
1681 _pvcam_init()
1682 except:
1683 pass
1684 # If no cameras detected, need to deinit DLL so it can be reinited to update count.
1685 if _cam_get_total().value == 0:
1686 _pvcam_uninit()
1687 raise microscope.InitialiseError("No cameras detected.")
1688 # Connect to the camera.
1689 _logger.info("DLL version: %s", _pvcam_get_ver().value)
1690 self._pv_name = _cam_get_name(self._index).value
1691 _logger.info("Initializing %s", self._pv_name)
1692 self.handle = _cam_open(self._pv_name, OPEN_EXCLUSIVE)
1693 PVCamera.open_cameras.append(self.handle)
1694 # Set up event callbacks. Tried to use the resume callback to reinit camera
1695 # after power loss, but any attempt to close/reopen the camera or deinit the
1696 # DLL throws a Windows Error 0xE06D7363.
1697 def _cb(event):
1698 _logger.info("Received %s event.", event)
1699 if event == "removed":
1700 _logger.critical("Can not re-init hardware. Exiting.")
1701 exit(-1)
1702 return
1703
1704 self._cbs = {
1705 "check": CALLBACK(lambda: _cb("check")),
1706 "resumed": CALLBACK(lambda: _cb("resumed")),
1707 "removed": CALLBACK(lambda: _cb("removed")),
1708 }
1709 _cam_register_callback(
1710 self.handle, PL_CALLBACK_CHECK_CAMS, self._cbs["check"]
1711 )
1712 _cam_register_callback(
1713 self.handle, PL_CALLBACK_CAM_REMOVED, self._cbs["removed"]
1714 )
1715 _cam_register_callback(
1716 self.handle, PL_CALLBACK_CAM_RESUMED, self._cbs["resumed"]
1717 )
1718 # Repopulate _params.
1719 self._params = {}
1720 for (param_id, name) in _param_to_name.items():
1721 try:
1722 p = PVParam.factory(self, param_id)
1723 except:
1724 _logger.warn("Skipping unsupported parameter %s.", name)
1725 continue
1726 if not p.dtype or not p.available:
1727 continue
1728 self._params[param_id] = p
1729 name = name[6:]
1730
1731 try:
1732 p.current
1733 except KeyError:
1734 # Raise these here, as the message is a tuple, not a str.
1735 raise
1736 except Exception as err:
1737 # Test on err.args prevents indexing into empty tuple.
1738 if err.args and not err.args[0].startswith("pvcam error 49"):
1739 _logger.warn(
1740 "Skipping parameter %s: not supported" " in python.",
1741 p.name,
1742 )
1743 continue
1744 self.add_setting(
1745 p.name,
1746 p.dtype,
1747 lambda p=p: p.current,
1748 p.set_value
1749 if p.access in [ACC_READ_WRITE, ACC_WRITE_ONLY]
1750 else None,
1751 lambda p=p: p.values,
1752 )
1753 if PARAM_GAIN_MULT_FACTOR in self._params:
1754 self.add_setting(
1755 "gain",
1756 self._params[PARAM_GAIN_MULT_FACTOR].dtype,
1757 lambda: self._params[PARAM_GAIN_MULT_FACTOR].current,
1758 self._params[PARAM_GAIN_MULT_FACTOR].set_value,
1759 self._params[PARAM_GAIN_MULT_FACTOR].values,
1760 )
1761
1762 if PARAM_PMODE in self._params:
1763 self.add_setting(
1764 "frame transfer mode",
1765 self._params[PARAM_PMODE].dtype,
1766 lambda: self._params[PARAM_PMODE].current,
1767 self._params[PARAM_PMODE].set_value,
1768 self._params[PARAM_PMODE].values,
1769 )
1770
1771 self.shape = (
1772 self._params[PARAM_PAR_SIZE].current,
1773 self._params[PARAM_SER_SIZE].current,
1774 )
1775 self.roi = microscope.ROI(0, 0, self.shape[0], self.shape[1])
1776
1777 # Populate readout modes by iterating over readout ports and speed
1778 # table entries.
1779 ro_ports = self._params[PARAM_READOUT_PORT].values
1781 self._readout_mode_parameters = []
1782 for i, port in ro_ports.items():
1783 self._params[PARAM_READOUT_PORT].set_value(i)
1784 ro_speeds = self._params[PARAM_SPDTAB_INDEX].values
1785 for j in range(ro_speeds[0], ro_speeds[1] + 1):
1786 self._params[PARAM_SPDTAB_INDEX].set_value(j)
1787 bit_depth = self._params[PARAM_BIT_DEPTH].current
1788 freq = 1e9 / self._params[PARAM_PIX_TIME].current
1789 if freq > 1e6:
1790 freq *= 1e-6
1791 prefix = "M"
1792 elif freq > 1e3:
1793 freq *= 1e-3
1794 prefix = "k"
1795 else:
1796 prefix = "Hz"
1797 mode_str = "%s, %s-bit, %s %sHz" % (
1798 port,
1799 bit_depth,
1800 freq,
1801 prefix,
1802 )
1803 self._readout_modes_readout_modes.append(mode_str)
1804 self._readout_mode_parameters.append(
1805 {"port": i, "spdtab_index": j}
1806 )
1807 # Set to default mode.
1809 self._params[PARAM_CLEAR_MODE].set_value(CLEAR_PRE_EXPOSURE_POST_SEQ)
1810
1811 @microscope.abc.keep_acquiring
1812 def set_readout_mode(self, index):
1813 """Set the readout mode and transform."""
1814 params = self._readout_mode_parameters[index]
1815 self._params[PARAM_READOUT_PORT].set_value(params["port"])
1816 self._params[PARAM_SPDTAB_INDEX].set_value(params["spdtab_index"])
1817 self._readout_mode_readout_mode = index
1818 # Update transforms, if available.
1819 chip = self._params[PARAM_CHIP_NAME].current
1820 new_readout_transform = None
1821 readout_map = READOUT_TRANSFORMS.get(chip, None)
1822 if readout_map:
1823 new_readout_transform = readout_map.get(params["port"], None)
1824 if new_readout_transform:
1825 self._set_readout_transform(new_readout_transform)
1826
1827 @microscope.abc.keep_acquiring
1828 def set_exposure_time(self, value):
1829 """Set the exposure time to value."""
1830 self.exposure_time = value
1831
1833 """Return the current exposure time.
1834
1835 Just return self.exposure_time, which is updated with the real
1836 value during _do_enable."""
1837 return self.exposure_time
1838
1840 """Return the cycle time.
1841
1842 Just return self.cycle_time, which is updated with the real
1843 value during _do_enable."""
1844 return self.cycle_time
1845
1846 @Pyro4.oneway
1847 def soft_trigger(self):
1848 """Expose software triggering to a client.
1849
1850 Deprecated, use trigger().
1851
1852 Trigger an exposure in TRIG_SOFT mode.
1853 Log some debugging stats in other trigger modes."""
1854 if self._trigger == TRIG_SOFT:
1855 _logger.debug("Received soft trigger ...")
1856 _exp_start_seq(
1857 self.handle, self._buffer.ctypes.data_as(ctypes.c_void_p)
1858 )
1859 else:
1860 cstatus, cbytes, cframes = _exp_check_cont_status(self.handle)
1861 status, bytes = _exp_check_status(self.handle)
1862
1863 _logger.debug(
1864 "Status checks\n"
1865 "check_cont: %s \t bytes: %d\tframes: %d\n"
1866 "check_status: %s \t bytes: %d\t",
1867 STATUS_STRINGS[cstatus.value],
1868 cbytes.value,
1869 cframes.value,
1870 STATUS_STRINGS[status.value],
1871 bytes.value,
1872 )
1873 return
1874
1875 @property
1876 def trigger_mode(self) -> microscope.TriggerMode:
1877 return PV_MODE_TO_TRIGGER[self._trigger][1]
1878
1879 @property
1880 def trigger_type(self) -> microscope.TriggerType:
1881 return PV_MODE_TO_TRIGGER[self._trigger][0]
1882
1884 self, ttype: microscope.TriggerType, tmode: microscope.TriggerMode
1885 ) -> None:
1886 try:
1887 self._trigger = TRIGGER_TO_PV_MODE[(ttype, tmode)]
1888 except KeyError:
1890 "no PVCam mode for %s and %s" % (ttype, tmode)
1891 )
1892
1893 def _do_trigger(self) -> None:
1894 _exp_start_seq(
1895 self.handle, self._buffer.ctypes.data_as(ctypes.c_void_p)
1896 )
def _set_readout_transform(self, new_transform)
Definition: abc.py:897
None set_exposure_time(self, float value)
Definition: abc.py:903
def set_readout_mode(self, description)
Definition: abc.py:876
None abort(self)
Definition: abc.py:588
None _put(self, data, timestamp)
Definition: abc.py:745
None add_setting(self, name, dtype, get_func, set_func, values, typing.Optional[typing.Callable[[], bool]] readonly=None)
Definition: abc.py:407
None initialize(self)
Definition: abc.py:339
None set_trigger(self, microscope.TriggerType ttype, microscope.TriggerMode tmode)
Definition: pvcam.py:1885
def set_exposure_time(self, value)
Definition: pvcam.py:1828
def set_readout_mode(self, index)
Definition: pvcam.py:1812
def set_value(self, new_value)
Definition: pvcam.py:1341
def factory(camera, param_id)
Definition: pvcam.py:1203
def _query(self, what=ATTR_CURRENT, force_query=False)
Definition: pvcam.py:1252
def set_value(self, new_value)
Definition: pvcam.py:1238
def set_value(self, new_value)
Definition: pvcam.py:1386