From 1ea7c3556c68968675a5a64244fe076f12dbaca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Thu, 2 Oct 2025 10:26:31 +0200 Subject: [PATCH 01/11] Fixed flt32/flt64 parameter values to be mapped to Python Float, not Long. --- src/pyvcam/pvcmodule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index 64721c6..e9b192f 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -657,9 +657,9 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) case TYPE_UNS64: return PyLong_FromUnsignedLongLong(paramValue.val_ulong64); case TYPE_FLT32: - return PyLong_FromDouble(paramValue.val_flt32); + return PyFloat_FromDouble(paramValue.val_flt32); case TYPE_FLT64: - return PyLong_FromDouble(paramValue.val_flt64); + return PyFloat_FromDouble(paramValue.val_flt64); case TYPE_BOOLEAN: if (paramValue.val_bool) Py_RETURN_TRUE; From 959ca2c06e16a4e3dcc4f57c08127af8d4a86f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Thu, 2 Oct 2025 10:59:49 +0200 Subject: [PATCH 02/11] Changed macros used for bool parameters to PyBool_FromLong to unify with others. --- src/pyvcam/pvcmodule.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index e9b192f..e12ed31 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -661,10 +661,7 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) case TYPE_FLT64: return PyFloat_FromDouble(paramValue.val_flt64); case TYPE_BOOLEAN: - if (paramValue.val_bool) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; + return PyBool_FromLong(paramValue.val_bool); // TODO: Add support for missing parameter types like smart streaming or ROI default: break; From ee3f3368fb490c87f596523d30361fc7f3f57ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Thu, 2 Oct 2025 16:50:49 +0200 Subject: [PATCH 03/11] Fixed pvc_get_param and pvc_set_param to support parameters of any type. The pvc_set_param supported only numeric parameters. Now both functions can handle also rgn_type for PARAM_ROI. --- src/pyvcam/pvcmodule.cpp | 182 +++++++++++++++++++++++++++++++-------- 1 file changed, 147 insertions(+), 35 deletions(-) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index e12ed31..00b9234 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -97,6 +97,7 @@ union ParamValue flt32 val_flt32; flt64 val_flt64; rs_bool val_bool; + rgn_type val_roi; }; class Camera @@ -358,6 +359,52 @@ static std::shared_ptr GetCamera(int16 hcam, bool setPyErr = true) return cam; } +/** Sets ValueError on error and returns rgn_type with all zeroes */ +static rgn_type PopulateRegion(PyObject* roiObj) +{ + rgn_type roi{ 0, 0, 0, 0, 0, 0 }; + + PyObject* s1Obj = PyObject_GetAttrString(roiObj, "s1"); + PyObject* s2Obj = PyObject_GetAttrString(roiObj, "s2"); + PyObject* sbinObj = PyObject_GetAttrString(roiObj, "sbin"); + PyObject* p1Obj = PyObject_GetAttrString(roiObj, "p1"); + PyObject* p2Obj = PyObject_GetAttrString(roiObj, "p2"); + PyObject* pbinObj = PyObject_GetAttrString(roiObj, "pbin"); + + if (s1Obj && s2Obj && sbinObj && p1Obj && p2Obj && pbinObj) + { + const long s1 = PyLong_AsLong(s1Obj); + const long s2 = PyLong_AsLong(s2Obj); + const long sbin = PyLong_AsLong(sbinObj); + const long p1 = PyLong_AsLong(p1Obj); + const long p2 = PyLong_AsLong(p2Obj); + const long pbin = PyLong_AsLong(pbinObj); + if ( s1 >= 0 && s1 <= (long)(std::numeric_limits::max)() + && s2 >= 0 && s2 <= (long)(std::numeric_limits::max)() + && sbin >= 1 && sbin <= (long)(std::numeric_limits::max)() + && p1 >= 0 && p1 <= (long)(std::numeric_limits::max)() + && p2 >= 0 && p2 <= (long)(std::numeric_limits::max)() + && pbin >= 1 && pbin <= (long)(std::numeric_limits::max)()) + { + roi.s1 = (uns16)s1; + roi.s2 = (uns16)s2; + roi.sbin = (uns16)sbin; + roi.p1 = (uns16)p1; + roi.p2 = (uns16)p2; + roi.pbin = (uns16)pbin; + } + } + + Py_XDECREF(s1Obj); + Py_XDECREF(s2Obj); + Py_XDECREF(sbinObj); + Py_XDECREF(p1Obj); + Py_XDECREF(p2Obj); + Py_XDECREF(pbinObj); + + return roi; +} + /** Sets ValueError on error and returns empty list */ static std::vector PopulateRegions(PyObject* roiListObj) { @@ -381,35 +428,11 @@ static std::vector PopulateRegions(PyObject* roiListObj) if (!roiObj) return ParseError(); - PyObject* s1Obj = PyObject_GetAttrString(roiObj, "s1"); - PyObject* s2Obj = PyObject_GetAttrString(roiObj, "s2"); - PyObject* sbinObj = PyObject_GetAttrString(roiObj, "sbin"); - PyObject* p1Obj = PyObject_GetAttrString(roiObj, "p1"); - PyObject* p2Obj = PyObject_GetAttrString(roiObj, "p2"); - PyObject* pbinObj = PyObject_GetAttrString(roiObj, "pbin"); - if (!s1Obj || !s2Obj || !sbinObj || !p1Obj || !p2Obj || !pbinObj) + rgn_type roi = PopulateRegion(roiObj); + if (roi.sbin == 0) // Invalid roi has all zeroes, let's check sbin only return ParseError(); - const long s1 = PyLong_AsLong(s1Obj); - const long s2 = PyLong_AsLong(s2Obj); - const long sbin = PyLong_AsLong(sbinObj); - const long p1 = PyLong_AsLong(p1Obj); - const long p2 = PyLong_AsLong(p2Obj); - const long pbin = PyLong_AsLong(pbinObj); - if ( s1 < 0 || s1 > (long)(std::numeric_limits::max)() - || s2 < 0 || s2 > (long)(std::numeric_limits::max)() - || sbin < 1 || sbin > (long)(std::numeric_limits::max)() - || p1 < 0 || p1 > (long)(std::numeric_limits::max)() - || p2 < 0 || p2 > (long)(std::numeric_limits::max)() - || pbin < 1 || pbin > (long)(std::numeric_limits::max)()) - return ParseError(); - - roiArray[i].s1 = (uns16)s1; - roiArray[i].s2 = (uns16)s2; - roiArray[i].sbin = (uns16)sbin; - roiArray[i].p1 = (uns16)p1; - roiArray[i].p2 = (uns16)p2; - roiArray[i].pbin = (uns16)pbin; + roiArray[i] = roi; } return roiArray; } @@ -662,13 +685,29 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) return PyFloat_FromDouble(paramValue.val_flt64); case TYPE_BOOLEAN: return PyBool_FromLong(paramValue.val_bool); - // TODO: Add support for missing parameter types like smart streaming or ROI + //case TYPE_SMART_STREAM_TYPE_PTR: + // // TODO: Add support for this parameter type + // break; + case TYPE_RGN_TYPE: + // Matches format in metadata and is compatible with Camera.RegionOfInterest + return Py_BuildValue("{s:H,s:H,s:H,s:H,s:H,s:H}", // dict + "s1", paramValue.val_roi.s1, + "s2", paramValue.val_roi.s2, + "sbin", paramValue.val_roi.sbin, + "p1", paramValue.val_roi.p1, + "p2", paramValue.val_roi.p2, + "pbin", paramValue.val_roi.pbin); + case TYPE_SMART_STREAM_TYPE_PTR: // TODO: Remove once implemented above + case TYPE_SMART_STREAM_TYPE: // Not used in PVCAM + case TYPE_VOID_PTR: // Not used in PVCAM + case TYPE_VOID_PTR_PTR: // Not used in PVCAM + case TYPE_RGN_TYPE_PTR: // Not used in PVCAM + case TYPE_RGN_LIST_TYPE: // Not used in PVCAM + case TYPE_RGN_LIST_TYPE_PTR: // Not used in PVCAM default: - break; + return PyErr_Format(PyExc_RuntimeError, + "Failed to match parameter type (%u).", (uns32)paramType); } - - return PyErr_Format(PyExc_RuntimeError, - "Failed to match parameter type (%u).", (uns32)paramType); } /** Sets a specified parameter to a given value. */ @@ -676,9 +715,8 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) { int16 hcam; uns32 paramId; - // TODO: Fix! The value parsed as 32-bit integer - void* paramValue; - if (!PyArg_ParseTuple(args, "hii", &hcam, ¶mId, ¶mValue)) + PyObject* paramValueObj; + if (!PyArg_ParseTuple(args, "hiO", &hcam, ¶mId, ¶mValueObj)) return ParamParseError(); rs_bool avail; @@ -689,6 +727,80 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) "Invalid setting for this camera. Parameter ID 0x%08X is not available.", paramId); + uns16 paramType; + if (!pl_get_param(hcam, paramId, ATTR_TYPE, ¶mType)) + return PvcamError(); + + ParamValue paramValue; + switch(paramType) + { + case TYPE_CHAR_PTR: { + Py_ssize_t size; + const char* str = PyUnicode_AsUTF8AndSize(paramValueObj, &size); + if (!str) + break; + const size_t strLen = (std::min)((size_t)size, sizeof(paramValue.val_str)); + memcpy(paramValue.val_str, str, strLen); + break; + } + case TYPE_ENUM: + paramValue.val_enum = (int32)PyLong_AsLong(paramValueObj); + break; + case TYPE_INT8: + paramValue.val_int8 = (int8)PyLong_AsLong(paramValueObj); + break; + case TYPE_UNS8: + paramValue.val_uns8 = (uns8)PyLong_AsUnsignedLong(paramValueObj); + break; + case TYPE_INT16: + paramValue.val_int16 = (int16)PyLong_AsLong(paramValueObj); + break; + case TYPE_UNS16: + paramValue.val_uns16 = (uns16)PyLong_AsUnsignedLong(paramValueObj); + break; + case TYPE_INT32: + paramValue.val_int32 = (int32)PyLong_AsLong(paramValueObj); + break; + case TYPE_UNS32: + paramValue.val_uns32 = (uns32)PyLong_AsUnsignedLong(paramValueObj); + break; + case TYPE_INT64: + paramValue.val_long64 = (long64)PyLong_AsLongLong(paramValueObj); + break; + case TYPE_UNS64: + paramValue.val_ulong64 = (ulong64)PyLong_AsUnsignedLongLong(paramValueObj); + break; + case TYPE_FLT32: + paramValue.val_flt32 = (flt32)PyLong_AsDouble(paramValueObj); + break; + case TYPE_FLT64: + paramValue.val_flt64 = (flt64)PyLong_AsDouble(paramValueObj); + break; + case TYPE_BOOLEAN: + paramValue.val_uns16 = (uns16)PyLong_AsUnsignedLong(paramValueObj); + break; + //case TYPE_SMART_STREAM_TYPE_PTR: + // // TODO: Add support for this parameter type + // break; + case TYPE_RGN_TYPE: + paramValue.val_roi = PopulateRegion(paramValueObj); + if (paramValue.val_roi.sbin == 0) // Invalid roi has all zeroes, let's check sbin only + return PyErr_Format(PyExc_ValueError, "Failed to parse ROI members."); + break; + case TYPE_SMART_STREAM_TYPE_PTR: // TODO: Remove once implemented above + case TYPE_SMART_STREAM_TYPE: // Not used in PVCAM + case TYPE_VOID_PTR: // Not used in PVCAM + case TYPE_VOID_PTR_PTR: // Not used in PVCAM + case TYPE_RGN_TYPE_PTR: // Not used in PVCAM + case TYPE_RGN_LIST_TYPE: // Not used in PVCAM + case TYPE_RGN_LIST_TYPE_PTR: // Not used in PVCAM + default: + return PyErr_Format(PyExc_RuntimeError, + "Failed to match parameter type (%u).", (uns32)paramType); + } + if (PyErr_Occurred()) + return NULL; + if (!pl_set_param(hcam, paramId, ¶mValue)) return PvcamError(); From bd16bc9d45b92ac97ed2749678d5c20914706457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Thu, 2 Oct 2025 16:57:17 +0200 Subject: [PATCH 04/11] Added live_roi property to Camera class and unit tests for it. --- src/pyvcam/camera.py | 8 ++++++++ tests/test_camera.py | 49 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/pyvcam/camera.py b/src/pyvcam/camera.py index fc822b5..cdd3744 100644 --- a/src/pyvcam/camera.py +++ b/src/pyvcam/camera.py @@ -1199,6 +1199,14 @@ def shape(self, roi_index=0): raise RuntimeError('Camera is not open') return self.__rois[roi_index].shape + @property + def live_roi(self): + return self.get_param(const.PARAM_ROI) + + @live_roi.setter + def live_roi(self, value): + self.set_param(const.PARAM_ROI, value) + @property def last_exp_time(self): return self.get_param(const.PARAM_EXPOSURE_TIME) diff --git a/tests/test_camera.py b/tests/test_camera.py index 7d4f0af..b499114 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -475,6 +475,55 @@ def test_get_exp_mode_no_open_fail(self): with self.assertRaises(RuntimeError): _ = self.test_cam.exp_mode + def test_get_live_roi(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_ROI): + self.test_cam.get_frame() # Just to apply all full sensor ROI + curr_roi = pvc.get_param(self.test_cam.handle, + const.PARAM_ROI, + const.ATTR_CURRENT) + self.assertEqual(curr_roi, self.test_cam.live_roi) + self.assertEqual(curr_roi['s2'], self.test_cam.sensor_size[0] - 1) + self.assertEqual(curr_roi['p2'], self.test_cam.sensor_size[1] - 1) + + def test_set_live_roi_idle(self): + self.test_cam.open() + if ( + pvc.check_param(self.test_cam.handle, const.PARAM_ROI) and + pvc.get_param(self.test_cam.handle, const.PARAM_ROI, const.ATTR_LIVE) + ): + self.test_cam.get_frame() # Just to apply all full sensor ROI + new_roi = self.test_cam.rois[0] + # Set the same ROI back, should always succeed, even outside acq. + self.test_cam.live_roi = new_roi + curr_roi = pvc.get_param(self.test_cam.handle, + const.PARAM_ROI, + const.ATTR_CURRENT) + self.assertEqual(curr_roi, self.test_cam.live_roi) + + new_roi.p2 = ((new_roi.p2 + 1) // 2) - 1 # Change to upper half + with self.assertRaises(RuntimeError): + # Set the ROI back, fails outside acq. + self.test_cam.live_roi = new_roi + + def test_set_live_roi_active(self): + self.test_cam.open() + if ( + pvc.check_param(self.test_cam.handle, const.PARAM_ROI) and + pvc.get_param(self.test_cam.handle, const.PARAM_ROI, const.ATTR_LIVE) + ): + self.test_cam.get_frame() # Just to apply all full sensor ROI + new_roi = self.test_cam.rois[0] + new_roi.p2 = ((new_roi.p2 + 1) // 2) - 1 # Change to upper half + # Start live acq. to apply live ROI, then stop immediately + self.test_cam.start_live() + self.test_cam.live_roi = new_roi + self.test_cam.finish() + curr_roi = pvc.get_param(self.test_cam.handle, + const.PARAM_ROI, + const.ATTR_CURRENT) + self.assertEqual(curr_roi, self.test_cam.live_roi) + def main(): unittest.main() From 1b64afb2efea93260a20a28b885f1fa958c63db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Thu, 2 Oct 2025 17:53:40 +0200 Subject: [PATCH 05/11] Fixed pvc_get_param to correctly handle parameter attributes with fixed type. For example a value for ATTR_AVAIL is always boolean regardless of reported parameter type. --- src/pyvcam/pvcmodule.cpp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index 00b9234..fc847bc 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -649,15 +649,36 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) "Invalid setting for this camera. Parameter ID 0x%08X is not available.", paramId); - uns16 paramType; - if (!pl_get_param(hcam, paramId, ATTR_TYPE, ¶mType)) - return PvcamError(); - ParamValue paramValue; if (!pl_get_param(hcam, paramId, paramAttr, ¶mValue)) return PvcamError(); - switch(paramType) + switch (paramAttr) + { + case ATTR_AVAIL: + case ATTR_LIVE: + return PyBool_FromLong(paramValue.val_bool); + case ATTR_TYPE: + case ATTR_ACCESS: + return PyLong_FromUnsignedLong(paramValue.val_uns16); + case ATTR_COUNT: + return PyLong_FromUnsignedLong(paramValue.val_uns32); + case ATTR_CURRENT: + case ATTR_DEFAULT: + case ATTR_MIN: + case ATTR_MAX: + case ATTR_INCREMENT: + break; // Handle each type below + default: + return PyErr_Format(PyExc_RuntimeError, + "Failed to match parameter attribute (%u).", (uns32)paramAttr); + } + + uns16 paramType; + if (!pl_get_param(hcam, paramId, ATTR_TYPE, ¶mType)) + return PvcamError(); + + switch (paramType) { case TYPE_CHAR_PTR: return PyUnicode_FromString(paramValue.val_str); @@ -732,7 +753,7 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) return PvcamError(); ParamValue paramValue; - switch(paramType) + switch (paramType) { case TYPE_CHAR_PTR: { Py_ssize_t size; From 7690082c1cec74daffa99c8ceaedc8b4fedd81d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Fri, 3 Oct 2025 20:55:48 +0200 Subject: [PATCH 06/11] Added support for smart stream parameters. --- pyproject.toml | 2 +- src/pyvcam/camera.py | 24 +++++++++ src/pyvcam/pvcmodule.cpp | 107 ++++++++++++++++++++++++++++++--------- tests/test_camera.py | 67 ++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 24 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3489e7..f73620c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "PyVCAM" -version = "2.3.0.dev0" +version = "2.3.1.dev0" description = "Python wrapper for PVCAM functionality" authors = [ {name = "Teledyne Photometrics", email = "photometrics.support@teledyne.com"}, diff --git a/src/pyvcam/camera.py b/src/pyvcam/camera.py index cdd3744..f256f42 100644 --- a/src/pyvcam/camera.py +++ b/src/pyvcam/camera.py @@ -1469,3 +1469,27 @@ def meta_data_enabled(self): @deprecated("Use 'metadata_enabled' property instead") def meta_data_enabled(self, value): self.metadata_enabled = value + + @property + def smart_stream_mode_enabled(self): + return self.get_param(const.PARAM_SMART_STREAM_MODE_ENABLED) + + @smart_stream_mode_enabled.setter + def smart_stream_mode_enabled(self, value): + self.set_param(const.PARAM_SMART_STREAM_MODE_ENABLED, value) + + @property + def smart_stream_mode(self): + return self.get_param(const.PARAM_SMART_STREAM_MODE) + + @smart_stream_mode.setter + def smart_stream_mode(self, value): + self.set_param(const.PARAM_SMART_STREAM_MODE, value) + + @property + def smart_stream_exp_params(self): + return self.get_param(const.PARAM_SMART_STREAM_EXP_PARAMS) + + @smart_stream_exp_params.setter + def smart_stream_exp_params(self, value): + self.set_param(const.PARAM_SMART_STREAM_EXP_PARAMS, value) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index fc847bc..f68336b 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -98,6 +98,7 @@ union ParamValue flt64 val_flt64; rs_bool val_bool; rgn_type val_roi; + smart_stream_type val_ss; }; class Camera @@ -437,6 +438,38 @@ static std::vector PopulateRegions(PyObject* roiListObj) return roiArray; } +/** Sets ValueError on error */ +static std::vector PopulateSsParams(PyObject* ssListObj) +{ + const Py_ssize_t count = PyList_Size(ssListObj); + if (count < 0 || count > (Py_ssize_t)(std::numeric_limits::max)()) + { + PyErr_Format(PyExc_ValueError, "Invalid SMART item count (%zd).", count); + return std::vector(); + } + + auto ParseError = []() { + // Override the error + PyErr_Format(PyExc_ValueError, "Failed to parse SMART items."); + return std::vector(); + }; + + std::vector ssArray((size_t)count); + for (Py_ssize_t i = 0; i < count; i++) + { + PyObject* ssObj = PyList_GetItem(ssListObj, i); + if (!ssObj) + return ParseError(); + + uns32 ssItem = (uns32)PyLong_AsUnsignedLong(ssObj); + if (PyErr_Occurred()) + return ParseError(); + + ssArray[i] = ssItem; + } + return ssArray; +} + static void NewFrameHandler(FRAME_INFO* pFrameInfo, void* context) { std::shared_ptr cam = GetCamera(pFrameInfo->hCam, false); @@ -638,24 +671,39 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) int16 hcam; uns32 paramId; int16 paramAttr; - if (!PyArg_ParseTuple(args, "hih", &hcam, ¶mId, ¶mAttr)) + if (!PyArg_ParseTuple(args, "hIh", &hcam, ¶mId, ¶mAttr)) return ParamParseError(); rs_bool avail; if (!pl_get_param(hcam, paramId, ATTR_AVAIL, &avail)) return PvcamError(); + if (paramAttr == ATTR_AVAIL) + return PyBool_FromLong(avail); if (!avail) return PyErr_Format(PyExc_AttributeError, "Invalid setting for this camera. Parameter ID 0x%08X is not available.", paramId); + uns16 paramType; + if (!pl_get_param(hcam, paramId, ATTR_TYPE, ¶mType)) + return PvcamError(); + ParamValue paramValue; + std::vector ssItems; // Helper container to hold data for SMART streaming + if (paramType == TYPE_SMART_STREAM_TYPE_PTR && paramAttr == ATTR_CURRENT) + { + if (!pl_get_param(hcam, paramId, ATTR_MAX, ¶mValue.val_ss.entries)) + return PvcamError(); + ssItems.resize(paramValue.val_ss.entries); + paramValue.val_ss.params = ssItems.data(); + } + if (!pl_get_param(hcam, paramId, paramAttr, ¶mValue)) return PvcamError(); switch (paramAttr) { - case ATTR_AVAIL: + //case ATTR_AVAIL: // Already handled above case ATTR_LIVE: return PyBool_FromLong(paramValue.val_bool); case ATTR_TYPE: @@ -664,20 +712,19 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) case ATTR_COUNT: return PyLong_FromUnsignedLong(paramValue.val_uns32); case ATTR_CURRENT: + break; // Handle all param types below case ATTR_DEFAULT: case ATTR_MIN: case ATTR_MAX: case ATTR_INCREMENT: - break; // Handle each type below + if (paramType == TYPE_SMART_STREAM_TYPE_PTR) + return PyLong_FromUnsignedLong(paramValue.val_ss.entries); + break; // Handle other param types below default: return PyErr_Format(PyExc_RuntimeError, "Failed to match parameter attribute (%u).", (uns32)paramAttr); } - uns16 paramType; - if (!pl_get_param(hcam, paramId, ATTR_TYPE, ¶mType)) - return PvcamError(); - switch (paramType) { case TYPE_CHAR_PTR: @@ -706,9 +753,22 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) return PyFloat_FromDouble(paramValue.val_flt64); case TYPE_BOOLEAN: return PyBool_FromLong(paramValue.val_bool); - //case TYPE_SMART_STREAM_TYPE_PTR: - // // TODO: Add support for this parameter type - // break; + case TYPE_SMART_STREAM_TYPE_PTR: { + PyObject* pySsList = PyList_New(paramValue.val_ss.entries); + if (!pySsList) + return NULL; + for (uns32 i = 0; i < paramValue.val_ss.entries; i++) + { + PyObject* pySsItem = PyLong_FromUnsignedLong(paramValue.val_ss.params[i]); + if (!pySsItem) + { + Py_DECREF(pySsList); + return NULL; + } + PyList_SET_ITEM(pySsList, (Py_ssize_t)i, pySsItem); + } + return pySsList; + } case TYPE_RGN_TYPE: // Matches format in metadata and is compatible with Camera.RegionOfInterest return Py_BuildValue("{s:H,s:H,s:H,s:H,s:H,s:H}", // dict @@ -718,7 +778,6 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) "p1", paramValue.val_roi.p1, "p2", paramValue.val_roi.p2, "pbin", paramValue.val_roi.pbin); - case TYPE_SMART_STREAM_TYPE_PTR: // TODO: Remove once implemented above case TYPE_SMART_STREAM_TYPE: // Not used in PVCAM case TYPE_VOID_PTR: // Not used in PVCAM case TYPE_VOID_PTR_PTR: // Not used in PVCAM @@ -737,7 +796,7 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) int16 hcam; uns32 paramId; PyObject* paramValueObj; - if (!PyArg_ParseTuple(args, "hiO", &hcam, ¶mId, ¶mValueObj)) + if (!PyArg_ParseTuple(args, "hIO", &hcam, ¶mId, ¶mValueObj)) return ParamParseError(); rs_bool avail; @@ -753,13 +812,14 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) return PvcamError(); ParamValue paramValue; + std::vector ssItems; // Helper container to hold data for SMART streaming switch (paramType) { case TYPE_CHAR_PTR: { Py_ssize_t size; const char* str = PyUnicode_AsUTF8AndSize(paramValueObj, &size); if (!str) - break; + return NULL; const size_t strLen = (std::min)((size_t)size, sizeof(paramValue.val_str)); memcpy(paramValue.val_str, str, strLen); break; @@ -800,15 +860,19 @@ static PyObject* pvc_set_param(PyObject* self, PyObject* args) case TYPE_BOOLEAN: paramValue.val_uns16 = (uns16)PyLong_AsUnsignedLong(paramValueObj); break; - //case TYPE_SMART_STREAM_TYPE_PTR: - // // TODO: Add support for this parameter type - // break; + case TYPE_SMART_STREAM_TYPE_PTR: { + ssItems = PopulateSsParams(paramValueObj); + if (PyErr_Occurred()) + return NULL; + paramValue.val_ss.entries = (uns16)ssItems.size(); + paramValue.val_ss.params = ssItems.data(); + break; + } case TYPE_RGN_TYPE: paramValue.val_roi = PopulateRegion(paramValueObj); if (paramValue.val_roi.sbin == 0) // Invalid roi has all zeroes, let's check sbin only return PyErr_Format(PyExc_ValueError, "Failed to parse ROI members."); break; - case TYPE_SMART_STREAM_TYPE_PTR: // TODO: Remove once implemented above case TYPE_SMART_STREAM_TYPE: // Not used in PVCAM case TYPE_VOID_PTR: // Not used in PVCAM case TYPE_VOID_PTR_PTR: // Not used in PVCAM @@ -833,17 +897,14 @@ static PyObject* pvc_check_param(PyObject* self, PyObject* args) { int16 hcam; uns32 paramId; - if (!PyArg_ParseTuple(args, "hi", &hcam, ¶mId)) + if (!PyArg_ParseTuple(args, "hI", &hcam, ¶mId)) return ParamParseError(); rs_bool avail; if (!pl_get_param(hcam, paramId, ATTR_AVAIL, &avail)) return PvcamError(); - if (avail) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; + return PyBool_FromLong(avail); } /** Sets up a live acquisition. */ @@ -1631,7 +1692,7 @@ static PyObject* pvc_read_enum(PyObject* self, PyObject* args) { int16 hcam; uns32 paramId; - if (!PyArg_ParseTuple(args, "hi", &hcam, ¶mId)) + if (!PyArg_ParseTuple(args, "hI", &hcam, ¶mId)) return ParamParseError(); rs_bool avail; diff --git a/tests/test_camera.py b/tests/test_camera.py index b499114..965b287 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -524,6 +524,73 @@ def test_set_live_roi_active(self): const.ATTR_CURRENT) self.assertEqual(curr_roi, self.test_cam.live_roi) + def test_get_smart_stream_mode_enabled(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_MODE_ENABLED): + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE_ENABLED, + const.ATTR_CURRENT) + self.assertEqual(cur_value, self.test_cam.smart_stream_mode_enabled) + + def test_set_smart_stream_mode_enabled(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_MODE_ENABLED): + for new_value in (True, False): + self.test_cam.smart_stream_mode_enabled = new_value + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE_ENABLED, + const.ATTR_CURRENT) + self.assertEqual(new_value, cur_value) + self.assertEqual(new_value, self.test_cam.smart_stream_mode_enabled) + + def test_get_smart_stream_mode(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_MODE): + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE, + const.ATTR_CURRENT) + self.assertEqual(cur_value, self.test_cam.smart_stream_mode) + + def test_set_smart_stream_mode(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_MODE): + min_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE, + const.ATTR_MIN) + max_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE, + const.ATTR_MAX) + for new_value in range(min_value, max_value + 1): + self.test_cam.smart_stream_mode = new_value + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_MODE, + const.ATTR_CURRENT) + self.assertEqual(new_value, cur_value) + self.assertEqual(new_value, self.test_cam.smart_stream_mode) + + def test_get_smart_stream_exp_params(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_EXP_PARAMS): + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_EXP_PARAMS, + const.ATTR_CURRENT) + self.assertEqual(cur_value, self.test_cam.smart_stream_exp_params) + + def test_set_smart_stream_exp_params(self): + self.test_cam.open() + if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_EXP_PARAMS): + max_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_EXP_PARAMS, + const.ATTR_MAX) + max_value -= 1 # Known bug, cameras report 16 but accept 15 only + new_value = list(range(max_value)) + self.test_cam.smart_stream_exp_params = new_value + cur_value = pvc.get_param(self.test_cam.handle, + const.PARAM_SMART_STREAM_EXP_PARAMS, + const.ATTR_CURRENT) + self.assertEqual(new_value, cur_value) + self.assertEqual(new_value, self.test_cam.smart_stream_exp_params) + def main(): unittest.main() From 87f87e906bd3b61098df033b9e61ff631dd09aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Mon, 6 Oct 2025 16:40:20 +0200 Subject: [PATCH 07/11] Fixed smart streaming min/max/inc/def values to return a list as the current attribute. --- src/pyvcam/pvcmodule.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/pyvcam/pvcmodule.cpp b/src/pyvcam/pvcmodule.cpp index f68336b..c1b0f96 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -690,12 +690,23 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) ParamValue paramValue; std::vector ssItems; // Helper container to hold data for SMART streaming - if (paramType == TYPE_SMART_STREAM_TYPE_PTR && paramAttr == ATTR_CURRENT) + if (paramType == TYPE_SMART_STREAM_TYPE_PTR) { - if (!pl_get_param(hcam, paramId, ATTR_MAX, ¶mValue.val_ss.entries)) - return PvcamError(); - ssItems.resize(paramValue.val_ss.entries); - paramValue.val_ss.params = ssItems.data(); + switch (paramAttr) + { + case ATTR_CURRENT: + case ATTR_DEFAULT: + case ATTR_MIN: + case ATTR_MAX: + case ATTR_INCREMENT: + if (!pl_get_param(hcam, paramId, ATTR_MAX, ¶mValue.val_ss.entries)) + return PvcamError(); + ssItems.resize(paramValue.val_ss.entries); + paramValue.val_ss.params = ssItems.data(); + break; + default: + break; + } } if (!pl_get_param(hcam, paramId, paramAttr, ¶mValue)) @@ -718,8 +729,9 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) case ATTR_MAX: case ATTR_INCREMENT: if (paramType == TYPE_SMART_STREAM_TYPE_PTR) - return PyLong_FromUnsignedLong(paramValue.val_ss.entries); - break; // Handle other param types below + for (uns32 i = 0; i < paramValue.val_ss.entries; i++) + paramValue.val_ss.params[i] = 0; + break; // Continue handling as other param types below default: return PyErr_Format(PyExc_RuntimeError, "Failed to match parameter attribute (%u).", (uns32)paramAttr); From d796da38ba54234187f5064f33b06a521e738247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Mon, 6 Oct 2025 16:41:03 +0200 Subject: [PATCH 08/11] Forgot to add unit test changes to previous commit. --- tests/test_camera.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_camera.py b/tests/test_camera.py index 965b287..3d03f97 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -579,11 +579,13 @@ def test_get_smart_stream_exp_params(self): def test_set_smart_stream_exp_params(self): self.test_cam.open() if pvc.check_param(self.test_cam.handle, const.PARAM_SMART_STREAM_EXP_PARAMS): + # ATTR_MAX returns a list too, only the list length is important max_value = pvc.get_param(self.test_cam.handle, const.PARAM_SMART_STREAM_EXP_PARAMS, const.ATTR_MAX) - max_value -= 1 # Known bug, cameras report 16 but accept 15 only - new_value = list(range(max_value)) + # Known bug, cameras report 16 but accept 15 values only + max_value_count = len(max_value) - 1 + new_value = list(range(max_value_count)) self.test_cam.smart_stream_exp_params = new_value cur_value = pvc.get_param(self.test_cam.handle, const.PARAM_SMART_STREAM_EXP_PARAMS, From e9a4a67571def1ab508cd6fa882d1756ee11220b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Mon, 6 Oct 2025 16:43:31 +0200 Subject: [PATCH 09/11] Added documentation for new properties. Also extracted repeated sentences from many properties and mentioned it only once before the table. --- docs/PyVCAM.md | 183 ++++++++++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 70 deletions(-) diff --git a/docs/PyVCAM.md b/docs/PyVCAM.md index a439fb3..2cd8e5f 100644 --- a/docs/PyVCAM.md +++ b/docs/PyVCAM.md @@ -93,11 +93,11 @@ cam.open() # Open the camera | `close` | Closes the camera. Will set `__handle` to the default value for a closed camera (`-1`) and will set `__is_open` to `False` if a successful call to PVCAM's close camera function is made. A `RuntimeError` will be raised if the call to PVCAM fails. For more information about how Python interacts with the PVCAM library, refer to the `pvcmodule.cpp` section of these notes. | ##### Basic Frame Acquisition -| Method | Description | -|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `get_frame` | Calls the `pvc` module's `get_frame` function with current camera settings to get a 2D numpy array of pixel data from a single snap image. This method can either be called with or without a given exposure time. If given, the method will use the given parameter. Otherwise, if left out, will use the internal `exp_time` property.

**Parameters:**
  • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| -| `get_sequence` | Calls the `pvc` module's `get_frame` function with cameras current settings in rapid-succession to get a 3D numpy array of pixel data from a single snap image. Multiple ROIs are not supported.

**Getting a sequence example:**
`# Given that the camera is already opened as openCam`
`stack = openCam.get_sequence(8) # Getting a sequence of 8 frames`
`firstFrame = stack[0] # Accessing 2D frames from 3D stack`
`lastFrame = stack[7]`

**Parameters:**
  • `num_frames` (int): The number of frames to be captured in the sequence.
  • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| -| `get_vtm_sequence` | Modified `get_sequence` to be used for Variable Timed Mode. Before calling it, set the camera's exposure mode to `'Variable Timed'`/`const.VARIABLE_TIMED_MODE`. If the camera doesn't support this mode or when the mode is not set, this function will emulate the same behavior as a sequence of single snaps with given exposure times. The timings will always start at the first given and keep looping around until it is captured the number of frames given. Multiple ROIs are not supported.

**Parameters:**
  • `time_list` (list of int): The exposure times to be used by the camera.
  • `exp_res` (int): The exposure time resolution. Supported are milliseconds (`0`/`const.EXP_RES_ONE_MILLISEC`), and for selected cameras also microseconds (`1`/`EXP_RES_ONE_MICROSEC`) and seconds (`2`/`EXP_RES_ONE_SEC`). Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) `PARAM_EXP_RES` and `PARAM_EXP_RES_INDEX`.
  • `num_frames` (int): The number of frames to be captured in the sequence.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `interval` (int): Time between each sequence frame (in milliseconds). Default is `None`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| +| Method | Description | +|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `get_frame` | Calls the `pvc` module's `get_frame` function with current camera settings to get a 2D numpy array of pixel data from a single snap image. This method can either be called with or without a given exposure time. If given, the method will use the given parameter. Otherwise, if left out, will use the internal `exp_time` property.

**Parameters:**
  • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| +| `get_sequence` | Calls the `pvc` module's `get_frame` function with cameras current settings in rapid-succession to get a 3D numpy array of pixel data from a single snap image. Multiple ROIs are not supported.

**Getting a sequence example:**
`# Given that the camera is already opened as openCam`
`stack = openCam.get_sequence(8) # Getting a sequence of 8 frames`
`firstFrame = stack[0] # Accessing 2D frames from 3D stack`
`lastFrame = stack[7]`

**Parameters:**
  • `num_frames` (int): The number of frames to be captured in the sequence.
  • Optional: `exp_time` (int): The exposure time to use. Default is `None` which will use the value set via `exp_time` property.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| +| `get_vtm_sequence` | Modified `get_sequence` to be used for Variable Timed Mode. Before calling it, set the camera's exposure mode to `'Variable Timed'`/`const.VARIABLE_TIMED_MODE`. If the camera doesn't support this mode or when the mode is not set, this function will emulate the same behavior as a sequence of single snaps with given exposure times. The timings will always start at the first given and keep looping around until it is captured the number of frames given. Multiple ROIs are not supported.

**Parameters:**
  • `time_list` (list of int): The exposure times to be used by the camera.
  • `exp_res` (int): The exposure time resolution. Supported are milliseconds (`0`/`const.EXP_RES_ONE_MILLISEC`), and for selected cameras also microseconds (`1`/`EXP_RES_ONE_MICROSEC`) and seconds (`2`/`EXP_RES_ONE_SEC`). Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) `PARAM_EXP_RES` and `PARAM_EXP_RES_INDEX`.
  • `num_frames` (int): The number of frames to be captured in the sequence.
  • Optional: `timeout_ms` (int): Duration to wait for new frames. Default is `WAIT_FOREVER`.
  • Optional: `interval` (int): Time between each sequence frame (in milliseconds). Default is `None`.
  • Optional: `reset_frame_counter` (bool): Resets `frame_count` returned by `poll_frame`. Default is `False`.
| ##### Advanced Frame Acquisition | Method | Description | @@ -121,15 +121,43 @@ cam.open() # Open the camera | `sw_trigger` | This method will issue a software trigger command to the camera. This command is only valid if the camera has been set use a software trigger. Refer to `sw_trigger.py` for an example. | ##### Parameters -| Method | Description | -|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `get_param` | Gets the current value of a specified attribute of given PVCAM parameter. Usually not called directly since the properties (see below) will handle most cases of getting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_get_param` function.

**Parameters**:
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
  • `param_attr` (int): The PVCAM defined value that corresponds to an attribute of a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available attribute ID values.
| -| `set_param` | Sets a specified camera parameter to a new value. Usually not called directly since the properties (see below) will handle most cases of setting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_set_param` function.

**Parameters:**
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and `constants.py` section for list of available parameter ID values.
  • `value` (various): The value to set the camera setting to. Make sure that its type closely matches the attribute's type so it can be properly set. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) for all possible attributes and their types.
| -| `check_param` | Checks if a camera parameter is available. This method is useful for checking certain features are available (such as post-processing, expose out mode). Returns `True` if available, `False` if not.

**Parameters:**
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/index.xhtml) and constants.py section for list of available parameter ID values.
| -| `get_post_processing_param` | Gets the current value of a specified post-processing parameter.

**Parameters**:
  • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
  • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
| -| `set_post_processing_param` | Sets the value of a specified post-processing parameter.

**Parameters**:
  • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
  • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
  • `value` (int): The value to be assigned to the post-processing parameter. Value must fall within the range provided by the `post_processing_table` property.
| -| `reset_pp` | If post-processing is available on the camera, the function will call `pvc.reset_pp` to reset all post-processing features back to their default state.

**Parameters:**
  • None
| -| `read_enum` | Returns all settings names paired with their values of a specified setting.

**Parameters:**
  • `param_id` (int): The parameter ID.
| +Each parameter is fully described by a set of values. These values are accessible via attributes and +`get_param` function. Some attributes provide a value with fixed type, some depend on parameter type. + +Attributes with fixed type: +- `ATTR_AVAIL` (bool): The `get_param` doesn't fail even for unavailable and unknown parameter ID. +- `ATTR_TYPE` (int): The `get_param` doesn't fail even for unavailable parameter. + An actual type for parameter attributes min., max., increment, default and current. +- `ATTR_ACCESS` (int): The `get_param` doesn't fail even for unavailable parameter. + Defines whether the parameter is read-only, read-write, etc. +- `ATTR_LIVE` (bool): If `True`, the parameter can be accessed also during acquisition. +- `ATTR_COUNT` (int): The meaning varies with parameter type. For example, it defines number + of enumeration items of `TYPE_ENUM` parameter (use `read_enum` function to get all items), + number of characters in string for `TYPE_CHAR_PTR` parameters. For numeric parameters it reports + number of valid values between min. and max. and given increment (e.g. if min=0, max=10, inc=2, + the count will be 6), or zero if either all values for given types are supported or the number + of valid values doesn't fit to 4-byte `uns32` C type. + +Remaining attributes (`ATTR_CURRENT`, `ATTR_MIN`, `ATTR_MAX`, `ATTR_INCREMENT`, `ATTR_DEFAULT`) +provide a value with type according to parameter type: +- `TYPE_INT*`, `TYPE_UNS*`, `TYPE_ENUM`: Returns an `int`. +- `TYPE_FLT*`: Returns a `float`. +- `TYPE_CHAR_PTR`: Returns a `str`. +- `TYPE_RGN_TYPE`: Returns a `dict` with values under keys `"s1"`, `"s2"`, `"sbin"`, `"p1"`, `"p2"`, `"pbin"`. +- `TYPE_SMART_STREAM_TYPE_PTR`: Returns a `list` of `int` values. + The list can be empty, or in case of `ATTR_MAX` it contains all zeroes where th number of zeroes + means the max. number of smart stream exposures.
+ **Warning**: It is known FW bug, the cameras actually supports max-1 values only. + +| Method | Description | +|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `get_param` | Gets the value of a specified attribute of given PVCAM parameter. The type of the value returned depends on parameter type and attribute as documented at the beginning of this chapter. Usually not called directly since the properties (see below) will handle most cases of getting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_get_param` function.

**Parameters**:
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) and `constants.py` section for list of available parameter ID values.
  • `param_attr` (int): The PVCAM defined value that corresponds to an attribute of a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) and `constants.py` section for list of available attribute ID values.
| +| `set_param` | Sets a specified camera parameter to a new value. Usually not called directly since the properties (see below) will handle most cases of setting camera parameters. However, not all cases may be covered by the properties and a direct call may need to be made to PVCAM's `pl_set_param` function.

**Parameters:**
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) and `constants.py` section for list of available parameter ID values.
  • `value` (various): The value to set the camera setting to. Make sure that its type closely matches the parameter type as documented at the beginning of this chapter.
| +| `check_param` | Checks if a camera parameter is available. This method is useful for checking certain features are available (such as post-processing, expose out mode). Returns `True` if available, `False` if not. It basically a helper that internally calls `get_param` with `ATTR_AVAIL` attribute.

**Parameters:**
  • `param_id` (int): The PVCAM defined value that corresponds to a parameter. Refer to the [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) and constants.py section for list of available parameter ID values.
| +| `read_enum` | Returns a dictionary with all enumeration names paired with their values.

**Parameters:**
  • `param_id` (int): The parameter ID.
| +| `get_post_processing_param` | Gets the current value of a specified post-processing parameter. It is a helper that utilizes `set_param` to select given feature and it's parameter by their indexes and the uses `get_param` to read the current value. For other attributes have look at `post_processing_table` property.

**Parameters**:
  • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
  • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
| +| `set_post_processing_param` | Sets the value of a specified post-processing parameter. It is a helper that utilizes `set_param` to select given feature and it's parameter by their indexes and the uses `set_param` to change the value.

**Parameters**:
  • `feature_name` (str): A string name for the post-processing feature using this parameter. Feature names can be determined from the `post_processing_table` property.
  • `param_name` (str): A string name for the post-processing parameter. Parameter names can be determined from the `post_processing_table` property.
  • `value` (int): The value to be assigned to the post-processing parameter. Value must fall within the range provided by the `post_processing_table` property.
| +| `reset_pp` | If post-processing is available on the camera, the function will call `pvc.reset_pp` to reset all post-processing features back to their default state.

**Parameters:**
  • None
| #### Properties All properties are accessed via getters and setters. This means that it will appear that we are @@ -156,62 +184,77 @@ cam.gain = current_gain # To call setter, simply assign new value to the proper ``` ##### List of Properties -| Property | Description | -|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `adc_offset` | (read-only) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the camera's current ADC offset value. Only CCD camera's have ADCs (analog-to-digital converters). | -| `binning` | (read-write) Returns or changes the current serial and parallel binning values in a tuple.

The setter can be either a tuple for the binning (x, y) or a single value and will set a square binning with the given number, for example `cam.binning = x` makes `cam.__binning = (x, x)`.

Binning cannot be changed directly on the camera; but is used for setting up acquisitions and returning correctly shaped images returned from `get_frame`. The setter has built in checking to see that the given binning it able to be used later. Binning settings for individual ROIs is not supported. | -| `binnings` | (read-only) Returns a list of supported combinations of serial and parallel binning factors if limited by the camera. If the camera supports arbitrary binning `None` is retuned. | -| `bit_depth` | (read-only) Returns the native bit depth of pixel data for images collected with this camera.
Bit depth cannot be changed directly; instead, users must select a desired speed that has the desired bit depth. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed is currently selected. | -| `bit_depth_host` | (read-only) Returns the bit depth of pixel data outputted to the host. This parameter differs from the `bit_depth` in a way that it reports the bit depth of the output frame - a frame that is delivered to the host. Since PVCAM supports various host side post processing features, the host bit depth may differ from the native camera bit depth, depending on what host-side post processing features are active.
As a general rule, the application should always rely on the host-specific parameters when identifying the output data format. The native parameters should be used only for informational purposes, e.g. to show the camera native format in the GUI. | -| `cam_fw` | (read-only) Returns the cameras current firmware version as a string. | -| `centroids_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the current centroids mode, `'Locate'`/`const.PL_CENTROIDS_MODE_LOCATE`, `'Track'`/`const.PL_CENTROIDS_MODE_TRACK` or `'Blob'`/`const.PL_CENTROIDS_MODE_BLOB`. | -| `centroids_modes` | (read-only) Returns a dictionary containing centroid modes supported by the camera. | -| `chip_name` | (read-only) Returns the camera sensor's name as a string. | -| `clear_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the current clear mode of the camera. Note that clear modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the clear mode of a camera, either the integer value or the name of the clear mode can be specified. Refer to `constants.py` for the names of the clear modes. | -| `clear_modes` | (read-only) Returns a dictionary containing clear modes supported by the camera. | -| `clear_time` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the last acquisition's clearing time as reported by the camera in microseconds. | -| `driver_version` | (read-only) Returns a formatted string containing the major, minor, and build version. When `get_param` is called on the device driver version, it returns a highly formatted 16 bit integer. The first 8 bits correspond to the major version, bits 9-12 are the minor version, and the last nibble is the build number. | -| `exp_mode` | (read-write): Returns or changes the current exposure mode of the camera. Note that exposure modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the exposure mode of a camera, either the integer value or the name of the expose out mode can be specified. Refer to `constants.py` for the names of the exposure modes. | -| `exp_modes` | (read-only) Returns a dictionary containing exposure modes supported by the camera. | -| `exp_out_mode` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns or changes the current expose out mode of the camera. Note that expose out modes have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the expose out mode of a camera, either the integer value or the name of the expose out mode can be specified. Refer to `constants.py` for the names of the expose out modes. | -| `exp_out_modes` | (read-only) Returns a dictionary containing exposure out modes supported by the camera. | -| `exp_res` | (Getter and setter) Returns/changes the current exposure resolution of a camera. Note that exposure resolutions have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the exposure resolution of a camera, either the integer value or the name of the resolution can be specified. Refer to `constants.py` for the names of the exposure resolutions. | -| `exp_res_index` | (read-only): Returns the current exposure resolution index. | -| `exp_resolutions` | (read-only) Returns a dictionary containing exposure resolutions supported by the camera. | -| `exp_time` | (read-write): Returns or changes the exposure time the camera will use if not given an exposure time. It is recommended to modify this value to modify your acquisitions for better abstraction. | -| `fan_speed` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the current fan speed setpoint of the camera. Note that fan speeds have names, but PVCAM interprets them as integer values. When called as a getter, the integer value will be returned to the user. However, when changing the fan speed of a camera, either the integer value or the name of the fan speed can be specified. Refer to `constants.py` for the names of the fan speeds. | -| `fan_speeds` | (read-only) Returns a dictionary containing fan speeds supported by the camera. | -| `gain` | (read-write) Returns or changes the current gain index for a camera. A `ValueError` will be raised if an invalid gain index is supplied to the setter. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. | -| `gain_name` | (read-only) Returns the name of currently selected gain via `gain` under selected port and speed. It is either hard-coded generic string or provided by the camera. | -| `handle` | (read-only) Returns the value currently stored inside the Camera's `__handle` instance variable. | -| `is_open` | (read-only) Returns the value currently stored inside the Camera's `__is_open` instance variable. | -| `last_exp_time` | (read-only) Returns the last exposure time the camera used for the last successful non-variable timed mode acquisition in what ever time resolution it was captured at. | -| `metadata_enabled` | (read-write): Returns or changes the embedded frame metadata availability. | -| `name` | (read-only) Returns the value currently stored inside the Camera's `__name` instance variable. | -| `pix_time` | (read-only) Returns the camera's pixel time, which is the inverse of the speed of the camera. Pixel time cannot be changed directly; instead users must select a desired speed that has the desired pixel time. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed table entry is currently selected. | -| `port_speed_gain_table` | (read-only) Returns a dictionary containing the port, speed and gain table, which gives information such as bit depth and pixel time for each readout port, speed and gain. | -| `post_processing_table` | (read-only) Returns a dictionary containing post-processing features and parameters as well as the minimum and maximum value for each parameter. | -| `post_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the last acquisition's post-trigger delay as reported by the camera in microseconds. | -| `pre_trigger_delay` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the last acquisition's pre-trigger delay as reported by the camera in microseconds | -| `prog_scan_mode` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the current programmable scan mode, `Auto`/`const.PL_SCAN_MODE_AUTO`, `Line Delay`/`const.PL_SCAN_MODE_PROGRAMMABLE_LINE_DELAY` or `Scan Width`/`const.PL_SCAN_MODE_PROGRAMMABLE_SCAN_WIDTH`. | -| `prog_scan_modes` | (read-only) Returns a dictionary containing programmable scan modes supported by the camera. | -| `prog_scan_dir` | (read-write) **Warning: Camera specific setting. Not all camera's support this parameter. If an unsupported camera attempts to access its readout_port, an AttributeError will be raised.**

Returns/changes the current programmable scan direction, `'Down'`/`const.PL_SCAN_DIRECTION_DOWN`, `'Up'`/`const.PL_SCAN_DIRECTION_UP` or `'Down/Up Alternate'`/`const.PL_SCAN_DIRECTION_DOWN_UP`. | -| `prog_scan_dirs` | (read-only) Returns a dictionary containing programmable scan directions supported by the camera. | -| `prog_scan_dir_reset` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes scan direction reset state of camera. The parameter is used with alternate scan directions (down-up) to reset the direction with every acquisition. | -| `prog_scan_line_delay` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the scan line delay. The parameter access mode depends on the `prog_scan_mode` selection. | -| `prog_scan_width` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the scan width. The parameter access mode depends on the `prog_scan_mode` selection. | -| `readout_port` | (read-write) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Some cameras may have many readout ports, which are output nodes from which a pixel stream can be read from. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. For more information about readout ports, refer to the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual. | -| `readout_ports` | (read-only) Returns a dictionary containing readout ports supported by the camera. | -| `readout_time` | (read-only): Returns the last acquisition's readout time as reported by the camera in microseconds. | -| `scan_line_time` | (Getter) **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the scan line time of camera in nano seconds. | -| `sensor_size` | (read-only) Returns the sensor size of the current camera in a tuple in the form (serial sensor size, parallel sensor size) | -| `serial_no` | (read-only) Returns the camera's serial number as a string. | -| `speed` | (read-write) Returns or changes the current numerical index of the speed table of a camera. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. See the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/_speed_table.xhtml) section inside the PVCAM User Manual for a detailed explanation about PVCAM speed tables. | -| `speed_name` | (read-only) Returns the name of currently selected speed via `speed` under selected port. It is either hard-coded generic string or provided by the camera. | -| `temp` | (read-only): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns the current temperature of a camera in Celsius. | -| `temp_setpoint` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns/changes the camera's temperature setpoint. The temperature setpoint is the temperature that a camera will attempt to keep its temperature (in Celsius) at. | -| `trigger_table` | (read-only) Returns a dictionary containing a table consisting of information of the last acquisition such as exposure time, readout time, clear time, pre-trigger delay, and post-trigger delay. If any of the parameters are unavailable, the dictionary item will be set to `'N/A'`. | -| `vtm_exp_time` | (read-write): **Warning: Camera specific setting. Not all cameras support this parameter. If an unsupported camera attempts to access it, an `AttributeError` will be raised.**

Returns or changes the variable timed exposure time the camera uses for the `'Variable Timed'` exposure mode.

Warning: New sequence acquisition must be started after setting this property to apply the value to the camera. Reading the value right after it was written will return a value from last VTM acquisition. If unsure, use `get_vtm_sequence` function instead. | +Some properties are camera-specific - not all cameras support related PVCAM parameter. +If an unsupported camera attempts to access it, an `AttributeError` will be raised. + +For each enumeration parameter there is a pair of properties - a plural form like `exp_modes` +that is a dictionary with enum item names and values, and single form like `exp_mode`. +PVCAM works with the second one via integer values. In Python, when called as a getter, +the integer value will be returned to the user. However, when changing the value, either +the integer value or the name can be specified.
+Refer to [PVCAM User Manual](https://docs.teledynevisionsolutions.com/pvcam-sdk/index.xhtml) +and `constants.py` for the predefines constants. + +| Property | Description | +|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `adc_offset` | (read-only) Returns the camera's current ADC offset value. Only CCD camera's have ADCs (analog-to-digital converters). | +| `binning` | (read-write) Returns or changes the current serial and parallel binning values in a tuple.

The setter can be either a tuple for the binning (x, y) or a single value and will set a square binning with the given number, i.e. `cam.binning = x` and `cam.binning = (x, x)` are equivalent.

Binning cannot be changed directly on the camera; but is used for setting up acquisitions and returning correctly shaped images returned from `get_frame`. The setter has built in checking to see that the given binning it able to be used later. Binning settings for individual ROIs is not supported. | +| `binnings` | (read-only) Returns a list of supported combinations of serial and parallel binning factors if limited by the camera. If the camera supports arbitrary binning `None` is retuned. | +| `bit_depth` | (read-only) Returns the native bit depth of pixel data for images collected with this camera.

Bit depth cannot be changed directly; instead, users must select a desired speed that has the desired bit depth. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/pvcam-sdk/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed is currently selected. | +| `bit_depth_host` | (read-only) Returns the bit depth of pixel data outputted to the host.

This parameter differs from the `bit_depth` in a way that it reports the bit depth of the output frame - a frame that is delivered to the host. Since PVCAM supports various host side post processing features, the host bit depth may differ from the native camera bit depth, depending on what host-side post processing features are active.

As a general rule, the application should always rely on the host-specific parameters when identifying the output data format. The native parameters should be used only for informational purposes, e.g. to show the camera native format in the GUI. | +| `cam_fw` | (read-only) Returns the cameras current firmware version as a string. | +| `centroids_mode` | (read-write, enum) Returns or changes the current centroids mode. See `centroid_modes` for the full list of supported values. | +| `centroids_modes` | (read-only) Returns a dictionary containing centroid modes supported by the camera. | +| `chip_name` | (read-only) Returns the camera sensor's name as a string. | +| `clear_mode` | (read-write, enum): Returns or changes the current clear mode of the camera.See `clear_modes` for the full list of supported values. | +| `clear_modes` | (read-only) Returns a dictionary containing clear modes supported by the camera. | +| `clear_time` | (read-only): Returns the last acquisition's clearing time as reported by the camera in microseconds. | +| `driver_version` | (read-only) Returns a formatted string containing the major, minor, and build version. When `get_param` is called on the device driver version, it returns a highly formatted 16 bit integer. The first 8 bits correspond to the major version, bits 9-12 are the minor version, and the last nibble is the build number. | +| `exp_mode` | (read-write, enum): Returns or changes the current exposure mode of the camera.See `exp_modes` for the full list of supported values. | +| `exp_modes` | (read-only) Returns a dictionary containing exposure modes supported by the camera. | +| `exp_out_mode` | (read-write, enum): Returns or changes the current expose out mode of the camera.See `exp_out_modes` for the full list of supported values. | +| `exp_out_modes` | (read-only) Returns a dictionary containing exposure out modes supported by the camera. | +| `exp_res` | (read-write, enum) Returns or changes the current exposure resolution of a camera.See `exp_resolutions` for the full list of supported values. For some older cameras this parameter might not be available. In this case camera uses `EXP_RES_ONE_MILLISEC` resolution. | +| `exp_res_index` | (read-only): Returns the current exposure resolution index. For some older cameras this parameter might not be available. In this case camera uses `EXP_RES_ONE_MILLISEC` resolution. | +| `exp_resolutions` | (read-only) Returns a dictionary containing exposure resolutions supported by the camera. | +| `exp_time` | (read-write): Returns or changes the exposure time the camera will use if not given an exposure time. It is recommended to modify this value to modify your acquisitions for better abstraction. | +| `fan_speed` | (read-write, enum): Returns or changes the current fan speed setpoint of the camera.See `fan_speeds` for the full list of supported values. | +| `fan_speeds` | (read-only) Returns a dictionary containing fan speeds supported by the camera. | +| `gain` | (read-write) Returns or changes the current gain index for a camera. A `ValueError` will be raised if an invalid gain index is supplied to the setter. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. | +| `gain_name` | (read-only) Returns the name of currently selected gain via `gain` under selected port and speed. It is either hard-coded generic string or provided by the camera. | +| `handle` | (read-only) Returns the value currently stored inside the Camera's `__handle` instance variable. | +| `is_open` | (read-only) Returns the value currently stored inside the Camera's `__is_open` instance variable. | +| `last_exp_time` | (read-only) Returns the last exposure time the camera used for the last successful non-variable timed mode acquisition in what ever time resolution it was captured at. | +| `live_roi` | (read-write): Returns the region of interest used in last acquisition or changes an ROI for currently running acquisition.

If supported by the camera, the related PVCAM parameter reports `True` for `ATTR_LIVE` and new value can be set during active acquisition only, otherwise an error is reported. It is because an ROI for new acquisition is set via `set_roi` function and passed to `pvc.start_live` or `pvc.start_seq` functions. If the camera doesn't support it, this property is read-only. | +| `metadata_enabled` | (read-write): Returns or changes the embedded frame metadata availability. | +| `name` | (read-only) Returns the value currently stored inside the Camera's `__name` instance variable. | +| `pix_time` | (read-only) Returns the camera's pixel time, which is the inverse of the speed of the camera.

Pixel time cannot be changed directly; instead users must select a desired speed that has the desired pixel time. Note that a camera may have additional speed table entries for different readout ports. See [Port and Speed Choices](https://docs.teledynevisionsolutions.com/pvcam-sdk/_speed_table.xhtml) section inside the PVCAM User Manual for a visual representation of a speed table and to see which settings are controlled by which speed table entry is currently selected. | +| `port_speed_gain_table` | (read-only) Returns a dictionary containing the port, speed and gain table, which gives information such as bit depth and pixel time for each readout port, speed and gain. | +| `post_processing_table` | (read-only) Returns a dictionary containing post-processing features and parameters as well as the minimum and maximum value for each parameter. | +| `post_trigger_delay` | (read-only): Returns the last acquisition's post-trigger delay as reported by the camera in microseconds. | +| `pre_trigger_delay` | (read-only): Returns the last acquisition's pre-trigger delay as reported by the camera in microseconds | +| `prog_scan_mode` | (read-write, enum) Returns or changes the current programmable scan mode. See `prog_scan_modes` for the full list of supported values. | +| `prog_scan_modes` | (read-only) Returns a dictionary containing programmable scan modes supported by the camera. | +| `prog_scan_dir` | (read-write, enum) Returns or changes the current programmable scan direction. See `prog_scan_dirs` for the full list of supported values. | +| `prog_scan_dirs` | (read-only) Returns a dictionary containing programmable scan directions supported by the camera. | +| `prog_scan_dir_reset` | (read-write) Returns or changes scan direction reset state of camera. The parameter is used with alternate scan directions (down-up) to reset the direction with every acquisition. | +| `prog_scan_line_delay` | (read-write) Returns or changes the scan line delay. The parameter access mode depends on the `prog_scan_mode` selection. | +| `prog_scan_width` | (read-write) Returns or changes the scan width. The parameter access mode depends on the `prog_scan_mode` selection. | +| `readout_port` | (read-write, enum) Some cameras may have many readout ports, which are output nodes from which a pixel stream can be read from. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. For more information about readout ports, refer to the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/pvcam-sdk/_speed_table.xhtml) section inside the PVCAM User Manual. See `readout_ports` for the full list of supported values. There are no predefined constants for this parameter. | +| `readout_ports` | (read-only) Returns a dictionary containing readout ports supported by the camera. | +| `readout_time` | (read-only): Returns the last acquisition's readout time as reported by the camera in microseconds. | +| `scan_line_time` | (Getter) Returns the scan line time of camera in nano seconds. | +| `sensor_size` | (read-only) Returns the sensor size of the current camera in a tuple in the form (serial/x sensor size, parallel/y sensor size) | +| `serial_no` | (read-only) Returns the camera's serial number as a string. | +| `smart_stream_mode_enabled` | (read-write) Enables or disables the [S.M.A.R.T. streaming](https://docs.teledynevisionsolutions.com/pvcam-sdk/_smart_streaming.xhtml) feature. | +| `smart_stream_mode` | (read-write) Returns or changes the current S.M.A.R.T. streaming mode. This parameter is not an enumeration, but see `PL_SMT_MODES` enum for the full list of supported values (`SMTMODE_*`). | +| `smart_stream_exp_params` | (read-write) Returns or changes the current list of S.M.A.R.T. streaming exposures. Please refer to [S.M.A.R.T. streaming](https://docs.teledynevisionsolutions.com/pvcam-sdk/_smart_streaming.xhtml) section in PVCAM User Manual for more details and possible scenarios. | +| `speed` | (read-write) Returns or changes the current numerical index of the speed table of a camera. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. See the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/pvcam-sdk/_speed_table.xhtml) section inside the PVCAM User Manual for a detailed explanation about PVCAM speed tables. | +| `speed_name` | (read-only) Returns the name of currently selected speed via `speed` under selected port. It is either hard-coded generic string or provided by the camera. | +| `temp` | (read-only): Returns the current temperature of a camera in Celsius. | +| `temp_setpoint` | (read-write): Returns or changes the camera's temperature setpoint. The temperature setpoint is the temperature that a camera will attempt to keep its temperature (in Celsius) at. | +| `trigger_table` | (read-only) Returns a dictionary containing a table consisting of information of the last acquisition such as exposure time, readout time, clear time, pre-trigger delay, and post-trigger delay. If any of the parameters are unavailable, the dictionary item will be set to `'N/A'`. | +| `vtm_exp_time` | (read-write): Returns or changes the exposure time the camera uses for the `'Variable Timed'` exposure mode. If the camera doesn't support VTM, this property is still available but the value is ignored.

**Warning**: New sequence acquisition must be started after setting this property to apply the value to the camera. Reading the value right after it was written will return a value from last VTM acquisition. If unsure, use `get_vtm_sequence` function instead. | ### `constants.py` aka `const` Module The `constants.py` is a large data file that contains various camera settings and internal PVCAM From 0a9ba6f32b214e9b28dca82b01fe50f1df300dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Mon, 6 Oct 2025 16:46:02 +0200 Subject: [PATCH 10/11] Clarified return value type of get_param in code documentation for developers. --- src/pyvcam/camera.py | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/pyvcam/camera.py b/src/pyvcam/camera.py index f256f42..3be3e8a 100644 --- a/src/pyvcam/camera.py +++ b/src/pyvcam/camera.py @@ -446,7 +446,47 @@ def check_frame_status(self): return status def get_param(self, param_id, param_attr=const.ATTR_CURRENT): - """Gets the current value of a specified parameter. + """Gets the value of a specified parameter and attribute. + + The type of the value returned depends on parameter type and attribute. + + Some attributes provide a value of the same type for all parameters: + + - ATTR_AVAIL: Always returns a `bool`. + It doesn't fail even for unavailable and unknown parameter ID. + - ATTR_TYPE: Always returns an `int`. + It doesn't fail even for unavailable parameter. + An actual type for parameter attributes min., max., increment, + default and current. + - ATTR_ACCESS: Always returns an `int`. + It doesn't fail even for unavailable parameter. + Defines whether the parameter is read-only, read-write, etc. + - ATTR_LIVE: Always returns a `bool`. + If True, the parameter can be accessed also during acquisition. + - ATTR_COUNT: Always return an `int`. + The meaning varies with parameter type. For example, + it defines number of enumeration items of TYPE_ENUM + parameter (use `read_enum` function to get all items), + number of characters in string for TYPE_CHAR_PTR parameters. + For numeric parameters it reports number of valid values + between min. and max. and given increment + (e.g. if min=0, max=10, inc=2, the count will be 6), + or zero if either all values for given types are supported + or the number of valid values doesn't fit `uns32` C type. + + Remaining attributes (ATTR_CURRENT, ATTR_MIN, ATTR_MAX, ATTR_INCREMENT, + ATTR_DEFAULT) provide a value with type according to parameter type: + + - TYPE_INT*, TYPE_UNS*, TYPE_ENUM: Returns an `int`. + - TYPE_FLT*: Returns a `float`. + - TYPE_CHAR_PTR: Returns a `str`. + - TYPE_RGN_TYPE: Returns a `dict` with keys `s1`, `s2`, `sbin`, `p1`, `p2`, `pbin`. + - TYPE_SMART_STREAM_TYPE_PTR: Returns a `list` of `int` values. + The list can be empty, or in case of ATTR_MAX it contains + all zeroes where th number of zeroes means the max. number + of smart stream exposures. + **Warning**: It is known FW bug, the cameras actually + supports max-1 values only. Parameter(s): param_id (int): The parameter to get. Refer to constants.py for @@ -456,7 +496,7 @@ def get_param(self, param_id, param_attr=const.ATTR_CURRENT): constants for each attribute. Returns: - Value of specified parameter. + Value of specified parameter and attribute. """ return pvc.get_param(self.__handle, param_id, param_attr) @@ -475,6 +515,7 @@ def set_param(self, param_id, value): param_id (int): An int that corresponds to a camera setting. Refer to constants.py for valid parameter values. value (Varies): The value to set the camera setting to. + See the get_param documentation for value type. """ pvc.set_param(self.__handle, param_id, value) From 55104599b66daae1dd1e6b56a0cdf7cd2ed02be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Han=C3=A1k?= Date: Mon, 6 Oct 2025 18:12:58 +0200 Subject: [PATCH 11/11] Deprecated scan_line_time property in favor of prog_scan_line_time to unify naming. --- docs/PyVCAM.md | 2 +- src/pyvcam/camera.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/PyVCAM.md b/docs/PyVCAM.md index 2cd8e5f..b2a59a9 100644 --- a/docs/PyVCAM.md +++ b/docs/PyVCAM.md @@ -239,11 +239,11 @@ and `constants.py` for the predefines constants. | `prog_scan_dirs` | (read-only) Returns a dictionary containing programmable scan directions supported by the camera. | | `prog_scan_dir_reset` | (read-write) Returns or changes scan direction reset state of camera. The parameter is used with alternate scan directions (down-up) to reset the direction with every acquisition. | | `prog_scan_line_delay` | (read-write) Returns or changes the scan line delay. The parameter access mode depends on the `prog_scan_mode` selection. | +| `prog_scan_line_time` | (read-only) Returns the scan line time of camera in nano seconds. | | `prog_scan_width` | (read-write) Returns or changes the scan width. The parameter access mode depends on the `prog_scan_mode` selection. | | `readout_port` | (read-write, enum) Some cameras may have many readout ports, which are output nodes from which a pixel stream can be read from. After changing `readout_port` it is strongly recommended to re-apply the settings of `speed` and `gain` exactly in that order. For more information about readout ports, refer to the [Port and Speed Choices](https://docs.teledynevisionsolutions.com/pvcam-sdk/_speed_table.xhtml) section inside the PVCAM User Manual. See `readout_ports` for the full list of supported values. There are no predefined constants for this parameter. | | `readout_ports` | (read-only) Returns a dictionary containing readout ports supported by the camera. | | `readout_time` | (read-only): Returns the last acquisition's readout time as reported by the camera in microseconds. | -| `scan_line_time` | (Getter) Returns the scan line time of camera in nano seconds. | | `sensor_size` | (read-only) Returns the sensor size of the current camera in a tuple in the form (serial/x sensor size, parallel/y sensor size) | | `serial_no` | (read-only) Returns the camera's serial number as a string. | | `smart_stream_mode_enabled` | (read-write) Enables or disables the [S.M.A.R.T. streaming](https://docs.teledynevisionsolutions.com/pvcam-sdk/_smart_streaming.xhtml) feature. | diff --git a/src/pyvcam/camera.py b/src/pyvcam/camera.py index 3be3e8a..065f823 100644 --- a/src/pyvcam/camera.py +++ b/src/pyvcam/camera.py @@ -1429,10 +1429,6 @@ def centroids_mode(self, key_or_value): self.set_param(const.PARAM_CENTROIDS_MODE, value) - @property - def scan_line_time(self): - return self.get_param(const.PARAM_SCAN_LINE_TIME) - @property def prog_scan_mode(self): # Camera specific setting: Will raise AttributeError if called with a @@ -1485,6 +1481,15 @@ def prog_scan_line_delay(self): def prog_scan_line_delay(self, value): self.set_param(const.PARAM_SCAN_LINE_DELAY, value) + @property + def prog_scan_line_time(self): + return self.get_param(const.PARAM_SCAN_LINE_TIME) + + @property + @deprecated("Use 'prog_scan_line_time' property instead") + def scan_line_time(self): + return self.prog_scan_line_time + @property def prog_scan_width(self): return self.get_param(const.PARAM_SCAN_WIDTH)