24"""pvcam library wrapper.
26This module exposes pvcam C library functions in python.
29 Support frame metadata. The following functions are still not implemented::
31 /*****************************************************************************/
32 /*****************************************************************************/
34 /* Frame metadata functions */
36 /*****************************************************************************/
37 /*****************************************************************************/
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
47 rs_bool PV_DECL pl_md_frame_decode (md_frame* pDstFrame, void* pSrcBuf, uns32 srcBufSize);
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.
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
85 rs_bool PV_DECL pl_md_frame_recompose (void* pDstBuf, uns16 offX, uns16 offY,
86 uns16 dstWidth, uns16 dstHeight,
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
97 @param roiCount Number of ROIs the structure should be prepared
for.
100 rs_bool PV_DECL pl_md_create_frame_struct_cont (md_frame** pFrame, uns16 roiCount);
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
113 rs_bool PV_DECL pl_md_create_frame_struct (md_frame** pFrame, void* pSrcBuf,
117 Releases the md_frame struct
118 @param pFrame a pointer to the previously allocated structure
120 rs_bool PV_DECL pl_md_release_frame_struct (md_frame* pFrame);
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
131 rs_bool PV_DECL pl_md_read_extended (md_ext_item_collection* pOutput, void* pExtMdPtr,
150_logger = logging.getLogger(__name__)
153# Readout transform mapping - {CHIP_NAME: {port: transform}}
154READOUT_TRANSFORMS = {"Evolve-5": {0: (0, 0, 0), 1: (1, 0, 0)}}
157# Base typedefs, from pvcam SDK master.h
158# typedef unsigned short rs_bool;
159rs_bool = ctypes.c_ushort
160# typedef signed char int8;
165int16 = ctypes.c_short
167uns16 = ctypes.c_ushort
169int32 = ctypes.c_int32
171uns32 = ctypes.c_uint32
173flt32 = ctypes.c_float
175flt64 = ctypes.c_double
177ulong64 = ctypes.c_ulonglong
179long64 = ctypes.c_longlong
181enumtype = ctypes.c_int32
190MAX_ALPHA_SER_NUM_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
235ACC_EXIST_CHECK_ONLY = 3
241IO_DIR_INPUT_OUTPUT = 2
245CLEAR_PRE_EXPOSURE = 1
246CLEAR_PRE_SEQUENCE = 2
247CLEAR_POST_SEQUENCE = 3
248CLEAR_PRE_POST_SEQUENCE = 4
249CLEAR_PRE_EXPOSURE_POST_SEQ = 5
259TRIGGER_FIRST_MODE = 3
261VARIABLE_TIMED_MODE = 5
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
279PL_TRIGTAB_SIGNAL_EXPOSE_OUT = 0
280PP_FEATURE_RING_FUNCTION = 0
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
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
336READOUT_NOT_ACTIVE = 0
337EXPOSURE_IN_PROGRESS = 1
338READOUT_IN_PROGRESS = 2
342ACQUISITION_IN_PROGRESS = 5
346CCS_HALT_CLOSE_SHTR = 2
348CCS_CLEAR_CLOSE_SHTR = 4
350CCS_CLEAR_OPEN_SHTR = 6
354BEGIN_END_FRAME_IRQS = 3
358EXP_RES_ONE_MILLISEC = 0
359EXP_RES_ONE_MICROSEC = 1
362SCR_POST_OPEN_SHTR = 1
366SCR_POST_INTEGRATE = 5
369SCR_PRE_CLOSE_SHTR = 8
370SCR_POST_CLOSE_SHTR = 9
373PL_CALLBACK_CHECK_CAMS = 2
374PL_CALLBACK_CAM_REMOVED = 3
375PL_CALLBACK_CAM_RESUMED = 4
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
406TYPE_VOID_PTR_PTR = 15
408TYPE_SMART_STREAM_TYPE = 17
409TYPE_SMART_STREAM_TYPE_PTR = 18
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
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
521 (
"FrameInfoGUID", PVCAM_FRAME_INFO_GUID),
524 (
"TimeStamp", long64),
525 (
"ReadoutTime", int32),
526 (
"TimeStampBOF", long64),
552io_struct._fields_ = [
556 (
"next", ctypes.POINTER(io_struct)),
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)),
577 (
"shutter_close_delay", uns16),
578 (
"shutter_open_delay", uns16),
586 (
"clear_count", uns16),
587 (
"preamp_delay", uns16),
588 (
"mpp_selectable", rs_bool),
589 (
"frame_selectable", rs_bool),
591 (
"open_shutter", uns16),
592 (
"mpp_mode", rs_bool),
593 (
"frame_transfer", rs_bool),
594 (
"alt_mode", rs_bool),
596 (
"io_hdr", ctypes.POINTER(io_list)),
602 (
"signature", uns32),
606 (
"timestampBOF", uns32),
607 (
"timestampEOF", uns32),
608 (
"timestampResNs", uns32),
609 (
"exposureTime", uns32),
610 (
"exposureTimeResN", uns32),
611 (
"roiTimestampResN", uns32),
615 (
"extendedMdSize", uns16),
616 (
"_reserved", uns8 * 8),
623 (
"timestampBOR", uns32),
624 (
"timestampEOR", uns32),
627 (
"extendedMdSize", uns16),
628 (
"_reserved", uns8 * 7),
636 (
"name", ctypes.c_char_p),
642 (
"tagInfo", ctypes.POINTER(md_ext_item_info)),
643 (
"value", ctypes.c_void_p),
649 (
"list", md_ext_item * PL_MD_EXT_TAGS_MAX_SUPPORTED),
650 (
"map", ctypes.POINTER(md_ext_item) * PL_MD_EXT_TAGS_MAX_SUPPORTED),
657 (
"header", ctypes.POINTER(md_frame_roi_header)),
658 (
"data", ctypes.c_void_p),
660 (
"extMdData", ctypes.c_void_p),
661 (
"extMdDataSize", uns16),
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),
677if os.name
in (
"nt",
"ce"):
678 if platform.architecture()[0] ==
"32bit":
679 _lib = ctypes.WinDLL(
"pvcam32")
681 _lib = ctypes.WinDLL(
"pvcam64")
683 _lib = ctypes.CDLL(
"pvcam.so")
686STRING = ctypes.c_char_p
695 def __init__(self, val):
697 self.val = ctypes.POINTER(val)
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)
705 ref = ctypes.byref(v)
713 def get_var(self, buf_len):
714 v = ctypes.create_string_buffer(buf_len)
722 """Strip meta info from OUTPUT and OUTSTRING instances."""
723 if isinstance(val, _meta):
730CALLBACK = ctypes.CFUNCTYPE(ctypes.c_void_p)
734 """Expose a DLL function to python.
736 (Again, largely nicked from PYME.)
"""
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]
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)]
753 docstring = name +
"\n\nArguments:\n===========\n"
754 for i
in range(len(args)):
756 if i < len(argnames):
758 docstring +=
"\t%s\t%s\n" % (args[i], an)
760 self.
f.__doc__ = docstring
762 def __call__(self, *args, **kwargs):
768 if "buf_len" in kwargs:
769 bs = kwargs[
"buf_len"]
770 elif self.
name ==
"pl_get_enum_param":
778 if isinstance(bs, ctypes._SimpleCData):
781 for j
in range(len(self.
inp)):
783 if self.
f.argtypes[j]
is CALLBACK
and not isinstance(
786 ars.append(CALLBACK(args[i]))
791 r, ar = self.
fargs[j].get_var(bs)
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)
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)
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
829"""DLL function imports."""
831dllFunc(
"pl_pvcam_get_ver", [
OUTPUT(uns16)], [
"version"])
832dllFunc(
"pl_pvcam_init")
833dllFunc(
"pl_pvcam_uninit")
835dllFunc(
"pl_cam_close", [int16], [
"hcam"])
839 [
"can_num",
"cam_name"],
840 buf_len=CAM_NAME_LEN,
853 [STRING,
OUTPUT(int16), int16],
854 [
"cam_name",
"hcam",
"o_mode"],
857 "pl_cam_register_callback",
858 [int16, int32, CALLBACK],
859 [
"hcam",
"event",
"Callback"],
862 "pl_cam_register_callback_ex",
863 [int16, int32, CALLBACK, ctypes.c_void_p],
864 [
"hcam",
"event",
"Callback",
"Context"],
867 "pl_cam_register_callback_ex2",
868 [int16, int32, CALLBACK],
869 [
"hcam",
"event",
"Callback"],
872 "pl_cam_register_callback_ex3",
873 [int16, int32, CALLBACK, ctypes.c_void_p],
874 [
"hcam",
"event",
"Callback",
"Context"],
877 "pl_cam_deregister_callback", [int16, ctypes.c_void_p], [
"hcam",
"event"]
883 [int16, uns32, int16,
OUTPUT(ctypes.c_void_p)],
884 [
"hcam",
"param_id",
"param_attrib",
"param_value"],
888 [int16, uns32, ctypes.c_void_p],
889 [
"hcam",
"param_id",
"param_value"],
893 [int16, uns32, uns32,
OUTPUT(int32), OUTSTRING, uns32],
894 [
"hcam",
"param_id",
"index",
"value",
"desc",
"length"],
897 "pl_enum_str_length",
898 [int16, uns32, uns32,
OUTPUT(uns32)],
899 [
"hcam",
"param_id",
"index",
"length"],
909 "pl_create_smart_stream_struct",
910 [
OUTPUT(smart_stream_type), uns16],
911 [
"pSmtStruct",
"entries"],
914 "pl_release_smart_stream_struct",
916 ctypes.POINTER(smart_stream_type),
923 "pl_create_frame_info_struct",
930 "pl_release_frame_info_struct",
932 ctypes.POINTER(FRAME_INFO),
938dllFunc(
"pl_exp_abort", [int16, int16], [
"hcam",
"cam_state"])
945 ctypes.POINTER(rgn_type),
960dllFunc(
"pl_exp_start_seq", [int16, ctypes.c_void_p], [
"hcam",
"pixel_stream"])
966 ctypes.POINTER(rgn_type),
984 [int16, ctypes.c_void_p, uns32],
985 [
"hcam",
"pixel_stream",
"size"],
988 "pl_exp_check_status",
990 [
"hcam",
"status",
"bytes_arrived"],
993 "pl_exp_check_cont_status",
995 [
"hcam",
"status",
"bytes_arrived",
"buffer_cnt"],
998 "pl_exp_check_cont_status_ex",
1004 ctypes.POINTER(FRAME_INFO),
1006 [
"hcam",
"status",
"byte_cnt",
"buffer_cnt",
"pFrameInfo"],
1009 "pl_exp_get_latest_frame",
1010 [int16,
OUTPUT(ctypes.c_void_p)],
1014 "pl_exp_get_latest_frame_ex",
1015 [int16,
OUTPUT(ctypes.c_void_p), ctypes.POINTER(FRAME_INFO)],
1016 [
"hcam",
"frame",
"pFrameInfo"],
1019 "pl_exp_get_oldest_frame",
1020 [int16,
OUTPUT(ctypes.c_void_p)],
1024 "pl_exp_get_oldest_frame_ex",
1025 [int16,
OUTPUT(ctypes.c_void_p), ctypes.POINTER(FRAME_INFO)],
1026 [
"hcam",
"frame",
"pFrameInfo"],
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"])
1032 "pl_exp_finish_seq", [int16, ctypes.c_void_p], [
"hcam",
"pixel_stream"]
1039 ATTR_AVAIL: rs_bool,
1043 ATTR_INCREMENT:
None,
1057 TYPE_UNS64: ulong64,
1059 TYPE_BOOLEAN: rs_bool,
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),
1065 TYPE_SMART_STREAM_TYPE: smart_stream_type,
1066 TYPE_SMART_STREAM_TYPE_PTR: ctypes.POINTER(smart_stream_type),
1075 TYPE_FLT64:
"float",
1081 TYPE_BOOLEAN:
"bool",
1083 TYPE_CHAR_PTR:
"str",
1084 TYPE_VOID_PTR:
None,
1085 TYPE_VOID_PTR_PTR:
None,
1087 TYPE_SMART_STREAM_TYPE:
None,
1088 TYPE_SMART_STREAM_TYPE_PTR:
None,
1089 TYPE_FLT32:
"float",
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,
1111 globals()[param]: param
1112 for param
in globals()
1113 if (param.startswith(
"PARAM_")
and param !=
"PARAM_NAME_LEN")
1117def get_param_type(param_id):
1118 """Return parameter type code (for C/DLL) for param_id."""
1120 return _typemap[param_id >> 24 & 255]
1123def get_param_dtype(param_id):
1124 """Return parameter dtype (for microscope settings) for param_id."""
1126 return _dtypemap[param_id >> 24 & 255]
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",
1143 """A microscope trigger mode using PVCAM PMODES."""
1145 def __init__(self, label, pv_mode):
1150 return "<%s: '%s'>" % (type(self).__name__, self.
label)
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),
1173PV_MODE_TO_TRIGGER = {
1174 TRIG_SOFT: (microscope.TriggerType.SOFTWARE, microscope.TriggerMode.ONCE),
1182 microscope.TriggerType.RISING_EDGE,
1183 microscope.TriggerMode.START,
1186 microscope.TriggerType.RISING_EDGE,
1187 microscope.TriggerMode.ONCE,
1190 microscope.TriggerType.RISING_EDGE,
1191 microscope.TriggerMode.BULB,
1196TRIGGER_TO_PV_MODE = {v: k
for k, v
in PV_MODE_TO_TRIGGER.items()}
1200 """A wrapper around PVCAM parameters."""
1204 """Create a PVParam or appropriate subclass"""
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,
1217 pvtype = __types__.get(param_id >> 24 & 255, PVParam)
1220 "Parameter %s not supported" % _param_to_name[param_id]
1222 return pvtype(camera, param_id)
1224 def __init__(self, camera, param_id):
1226 self.
cam = weakref.proxy(camera)
1228 self.
name = _param_to_name[param_id]
1229 self.
_pvtype = param_id >> 24 & 255
1230 if self.
name ==
"PARAM_READOUT_TIME":
1239 """Set a parameter value.
1241 Subclasses should do whatever processing they need on new_value,
1242 then call super().set_value(new_value)"""
1244 ref = ctypes.byref(new_value)
1247 ref = ctypes.byref(self.
_ctype(new_value))
1250 self.
_query(force_query=
True)
1252 def _query(self, what=ATTR_CURRENT, force_query=False):
1253 """Query the DLL for an attribute for this parameter.
1255 This returns pythonic types, not ctypes.
"""
1258 if self.
cam._acquiring
and not force_query:
1259 return self.
__cache.get(key,
None)
1260 if what == ATTR_AVAIL:
1264 "Parameter %s is not available" % self.
name
1266 rtype = _attr_map[what]
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]
1273 "pvcam: parameter %s not supported in python." % self.
name
1276 result = _get_param(
1277 self.
cam.handle, self.
param_id, what, buf_len=buf_len
1279 except Exception
as e:
1282 result = result.value
1285 result = _get_param(self.
cam.handle, self.
param_id, what)
1286 except Exception
as e:
1289 result = ctypes.POINTER(self.
_ctype)(result).contents.value
1291 if err
and err.args
and err.args[0].startswith(
"pvcam error 49"):
1293 "Parameter %s not available due to camera state.", self.
name
1304 """Return parameter access attribute."""
1306 _get_param(self.
cam.handle, self.
param_id, ATTR_ACCESS).value
1311 """Return whether or not parameter is available on hardware."""
1313 _get_param(self.
cam.handle, self.
param_id, ATTR_AVAIL).value
1318 """Return count of parameter enum entries."""
1320 _get_param(self.
cam.handle, self.
param_id, ATTR_COUNT).value
1325 """Get parameter min and max values.
1327 Subclasses for strings
and enum override this.
"""
1332 """Return the current (or cached) parameter value.
1334 Subclasses should override this for more complex data types.
"""
1339 """PVParam subclass for enums"""
1342 """Set an enum parameter value."""
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)
1354 if desc
and desc
in descriptions:
1355 new_index = descriptions.index(desc)
1356 new_value = values[new_index]
1359 "Could not find description '%s' for enum %s."
1366 """Return the current (or cached) enum parameter value."""
1368 return int(self.
_query()
or 0)
1372 """Get allowable enum 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(
1379 values[value.value] = desc.value.decode()
1384 """PVParam subclass for strings"""
1387 """Set a string parameter value"""
1388 if hasattr(new_value,
"encode"):
1389 new_value = new_value.encode()
1394 """Return the current (or cached) string parameter value."""
1395 return self.
_query().decode()
1399 """Get allowable string length."""
1400 values = _length_map[self.
param_id]
or 0
1408 """Implements the CameraDevice interface for the pvcam library."""
1413 def __init__(self, index=0, **kwargs):
1414 super().__init__(index=index, **kwargs)
1420 self.
shape = (
None,
None)
1422 self.
roi = (
None,
None,
None,
None)
1448 lambda value: setattr(self,
"_trigger", value),
1449 {k: v.label
for k, v
in TRIGGER_MODES.items()},
1452 "circular buffer length",
1455 lambda value: setattr(self,
"_circ_buffer_length", value),
1463 """Return a rgn_type for current roi and binning settings."""
1466 self.
roi.left + self.
roi.width - 1,
1469 self.
roi.top + self.
roi.height - 1,
1473 """Private methods, called here and within super classes."""
1475 def _fetch_data(self):
1476 """Fetch data - for use in fetch_loop."""
1480 def _do_enable(self):
1481 """Enable the camera hardware and make ready to respond to triggers.
1483 Return True if successful,
False if not.
"""
1487 self.
_params[PARAM_EXP_RES].set_value(EXP_RES_ONE_MICROSEC)
1490 self.
_params[PARAM_EXP_RES].set_value(EXP_RES_ONE_MILLISEC)
1495 buffer_dtype =
"uint16"
1496 if self.
_params[PARAM_BIT_DEPTH].current == 8:
1497 buffer_dtype =
"uint8"
1505 """Soft trigger mode end-of-frame callback."""
1506 timestamp = time.time()
1508 _logger.debug(
"Fetched single frame.")
1509 _exp_finish_seq(self.
handle, CCS_CLEAR)
1510 self.
_put(frame, timestamp)
1515 _cam_register_callback(
1518 nbytes = _exp_setup_seq(
1523 TRIGGER_MODES[self.
_trigger].pv_mode,
1531 np.empty(buffer_shape, dtype=buffer_dtype),
1532 requirements=[
"C_CONTIGUOUS",
"ALIGNED",
"OWNDATA"],
1540 if buffer_dtype ==
"uint8":
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),
1550 frame = np.ctypeslib.as_array(
1551 frame_p, (self.
roi[2], self.
roi[3])
1553 _logger.debug(
"Fetched frame from circular buffer.")
1554 self.
_put(frame, timestamp)
1559 _cam_register_callback(
1568 np.empty(buffer_shape, dtype=buffer_dtype),
1569 requirements=[
"C_CONTIGUOUS",
"ALIGNED",
"OWNDATA"],
1571 nbytes = _exp_setup_cont(
1575 TRIGGER_MODES[self.
_trigger].pv_mode,
1581 t_readback = self.
_params[PARAM_EXPOSURE_TIME].current
1582 t_resolution = self.
_params[PARAM_EXP_RES].current
1584 EXP_RES_ONE_SEC: 1.0,
1585 EXP_RES_ONE_MILLISEC: 1e-3,
1586 EXP_RES_ONE_MICROSEC: 1e-6,
1588 if isinstance(t_resolution, tuple):
1589 self.
exposure_time = t_readback * multipliers[t_resolution[0]]
1595 + 1e-6 * self.
_params[PARAM_READOUT_TIME].current
1600 self.
_params[PARAM_EXP_TIME].set_value(t_exp)
1606 self.
_buffer.ctypes.data_as(ctypes.c_void_p),
1613 def _do_disable(self):
1614 """Disable the hardware for a short period of inactivity."""
1616 _cam_deregister_callback(self.
handle, PL_CALLBACK_EOF)
1618 def _do_shutdown(self) -> None:
1619 """Disable the hardware for a prolonged period of inactivity."""
1622 PVCamera.open_cameras.remove(self.
handle)
1623 if not PVCamera.open_cameras:
1624 _logger.info(
"No more open cameras - calling _pvcam_uninit.")
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.
"""
1631 def _get_sensor_shape(self):
1632 """Return the sensor shape (width, height)."""
1635 def _get_binning(self):
1636 """Return the current binning (horizontal, vertical)."""
1639 @microscope.abc.keep_acquiring
1640 def _set_binning(self, binning):
1641 """Set binning to (h, v)."""
1646 """Return the current ROI (left, top, width, height)."""
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.")
1658 """Public methods, callable from client."""
1661 """Get hardware's unique identifier."""
1662 return self.
_params[PARAM_HEAD_SER_NUM_ALPHA].current
1665 """Abort acquisition.
1667 This should put the camera into a state in which settings can
1670 _exp_finish_seq(self.
handle, CCS_CLEAR)
1672 _exp_stop_cont(self.
handle, CCS_CLEAR)
1673 _exp_abort(self.
handle, CCS_HALT)
1676 def initialize(self):
1677 """Initialise the camera."""
1679 if not PVCamera.open_cameras:
1685 if _cam_get_total().value == 0:
1689 _logger.info(
"DLL version: %s", _pvcam_get_ver().value)
1691 _logger.info(
"Initializing %s", self.
_pv_name)
1693 PVCamera.open_cameras.append(self.
handle)
1698 _logger.info(
"Received %s event.", event)
1699 if event ==
"removed":
1700 _logger.critical(
"Can not re-init hardware. Exiting.")
1705 "check": CALLBACK(
lambda: _cb(
"check")),
1706 "resumed": CALLBACK(
lambda: _cb(
"resumed")),
1707 "removed": CALLBACK(
lambda: _cb(
"removed")),
1709 _cam_register_callback(
1710 self.
handle, PL_CALLBACK_CHECK_CAMS, self.
_cbs[
"check"]
1712 _cam_register_callback(
1713 self.
handle, PL_CALLBACK_CAM_REMOVED, self.
_cbs[
"removed"]
1715 _cam_register_callback(
1716 self.
handle, PL_CALLBACK_CAM_RESUMED, self.
_cbs[
"resumed"]
1720 for (param_id, name)
in _param_to_name.items():
1722 p = PVParam.factory(self, param_id)
1724 _logger.warn(
"Skipping unsupported parameter %s.", name)
1726 if not p.dtype
or not p.available:
1736 except Exception
as err:
1738 if err.args
and not err.args[0].startswith(
"pvcam error 49"):
1740 "Skipping parameter %s: not supported" " in python.",
1747 lambda p=p: p.current,
1749 if p.access
in [ACC_READ_WRITE, ACC_WRITE_ONLY]
1751 lambda p=p: p.values,
1753 if PARAM_GAIN_MULT_FACTOR
in self.
_params:
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,
1762 if PARAM_PMODE
in self.
_params:
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,
1772 self.
_params[PARAM_PAR_SIZE].current,
1773 self.
_params[PARAM_SER_SIZE].current,
1779 ro_ports = self.
_params[PARAM_READOUT_PORT].values
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
1797 mode_str =
"%s, %s-bit, %s %sHz" % (
1805 {
"port": i,
"spdtab_index": j}
1809 self.
_params[PARAM_CLEAR_MODE].set_value(CLEAR_PRE_EXPOSURE_POST_SEQ)
1811 @microscope.abc.keep_acquiring
1813 """Set the readout mode and transform."""
1815 self.
_params[PARAM_READOUT_PORT].set_value(params[
"port"])
1816 self.
_params[PARAM_SPDTAB_INDEX].set_value(params[
"spdtab_index"])
1819 chip = self.
_params[PARAM_CHIP_NAME].current
1820 new_readout_transform =
None
1821 readout_map = READOUT_TRANSFORMS.get(chip,
None)
1823 new_readout_transform = readout_map.get(params[
"port"],
None)
1824 if new_readout_transform:
1827 @microscope.abc.keep_acquiring
1829 """Set the exposure time to value."""
1833 """Return the current exposure time.
1835 Just return self.
exposure_time, which
is updated
with the real
1836 value during _do_enable.
"""
1840 """Return the cycle time.
1842 Just return self.
cycle_time, which
is updated
with the real
1843 value during _do_enable.
"""
1848 """Expose software triggering to a client.
1852 Trigger an exposure in TRIG_SOFT mode.
1853 Log some debugging stats
in other trigger modes.
"""
1855 _logger.debug(
"Received soft trigger ...")
1860 cstatus, cbytes, cframes = _exp_check_cont_status(self.
handle)
1861 status, bytes = _exp_check_status(self.
handle)
1865 "check_cont: %s \t bytes: %d\tframes: %d\n"
1866 "check_status: %s \t bytes: %d\t",
1867 STATUS_STRINGS[cstatus.value],
1870 STATUS_STRINGS[status.value],
1876 def trigger_mode(self) -> microscope.TriggerMode:
1877 return PV_MODE_TO_TRIGGER[self.
_trigger][1]
1880 def trigger_type(self) -> microscope.TriggerType:
1881 return PV_MODE_TO_TRIGGER[self.
_trigger][0]
1887 self.
_trigger = TRIGGER_TO_PV_MODE[(ttype, tmode)]
1890 "no PVCam mode for %s and %s" % (ttype, tmode)
1893 def _do_trigger(self) -> None:
def _set_readout_transform(self, new_transform)
None set_exposure_time(self, float value)
def set_readout_mode(self, description)
None _put(self, data, timestamp)
None add_setting(self, name, dtype, get_func, set_func, values, typing.Optional[typing.Callable[[], bool]] readonly=None)
None set_trigger(self, microscope.TriggerType ttype, microscope.TriggerMode tmode)
def set_exposure_time(self, value)
def set_readout_mode(self, index)
def get_exposure_time(self)
def set_value(self, new_value)
def factory(camera, param_id)
def _query(self, what=ATTR_CURRENT, force_query=False)
def set_value(self, new_value)
def set_value(self, new_value)