diff --git a/docs/PyVCAM.md b/docs/PyVCAM.md index a439fb3..b2a59a9 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:**
| -| `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:**
| -| `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:**
| +| 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:**
| +| `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:**
| +| `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:**
| ##### 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**:
| -| `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:**
| -| `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:**
| -| `get_post_processing_param` | Gets the current value of a specified post-processing parameter.

**Parameters**:
| -| `set_post_processing_param` | Sets the value of a specified post-processing parameter.

**Parameters**:
| -| `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:**
| -| `read_enum` | Returns all settings names paired with their values of a specified setting.

**Parameters:**
| +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**:
| +| `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:**
| +| `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:**
| +| `read_enum` | Returns a dictionary with all enumeration names paired with their values.

**Parameters:**
| +| `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**:
| +| `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**:
| +| `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:**
| #### 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_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. | +| `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 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 fc822b5..065f823 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) @@ -1199,6 +1240,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) @@ -1380,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 @@ -1436,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) @@ -1461,3 +1515,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 64721c6..c1b0f96 100644 --- a/src/pyvcam/pvcmodule.cpp +++ b/src/pyvcam/pvcmodule.cpp @@ -97,6 +97,8 @@ union ParamValue flt32 val_flt32; flt64 val_flt64; rs_bool val_bool; + rgn_type val_roi; + smart_stream_type val_ss; }; class Camera @@ -358,6 +360,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,37 +429,45 @@ 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)()) + roiArray[i] = roi; + } + 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(); - 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; + ssArray[i] = ssItem; } - return roiArray; + return ssArray; } static void NewFrameHandler(FRAME_INFO* pFrameInfo, void* context) @@ -615,12 +671,14 @@ 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.", @@ -631,10 +689,55 @@ static PyObject* pvc_get_param(PyObject* self, PyObject* args) return PvcamError(); ParamValue paramValue; + std::vector ssItems; // Helper container to hold data for SMART streaming + if (paramType == TYPE_SMART_STREAM_TYPE_PTR) + { + 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)) return PvcamError(); - switch(paramType) + switch (paramAttr) + { + //case ATTR_AVAIL: // Already handled above + 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: + break; // Handle all param types below + case ATTR_DEFAULT: + case ATTR_MIN: + case ATTR_MAX: + case ATTR_INCREMENT: + if (paramType == TYPE_SMART_STREAM_TYPE_PTR) + 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); + } + + switch (paramType) { case TYPE_CHAR_PTR: return PyUnicode_FromString(paramValue.val_str); @@ -657,21 +760,46 @@ 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; - else - Py_RETURN_FALSE; - // TODO: Add support for missing parameter types like smart streaming or ROI + return PyBool_FromLong(paramValue.val_bool); + 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 + "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: // 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. */ @@ -679,9 +807,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; @@ -692,6 +819,85 @@ 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; + 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) + return NULL; + 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: { + 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: // 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(); @@ -703,17 +909,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. */ @@ -1501,7 +1704,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 7d4f0af..3d03f97 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -475,6 +475,124 @@ 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 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): + # 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) + # 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, + const.ATTR_CURRENT) + self.assertEqual(new_value, cur_value) + self.assertEqual(new_value, self.test_cam.smart_stream_exp_params) + def main(): unittest.main()