pyhikrobot 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hikrobot/__init__.py ADDED
@@ -0,0 +1,97 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Thin, zero-copy Python bindings for Hikrobot machine-vision cameras (MVS SDK).
3
+
4
+ Importing this package never loads the vendor SDK: the shared library is located and
5
+ opened lazily on first real use, so ``import hikrobot`` succeeds on machines with no
6
+ SDK and no camera attached. A missing SDK surfaces as :class:`SDKNotFoundError` at
7
+ call time.
8
+
9
+ Every failure derives from :class:`HikrobotError`. A status returned by the SDK becomes a
10
+ :class:`StatusError` subclass chosen by the code; the raw ``MV_E_*`` values stay internal
11
+ and are reachable through :attr:`StatusError.status` and :attr:`StatusError.name`.
12
+ """
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ __all__ = [
17
+ "AccessDeniedError",
18
+ "BufferInUseError",
19
+ "BufferReleasedError",
20
+ "CallOrderError",
21
+ "Camera",
22
+ "CameraStateError",
23
+ "CameraTimeoutError",
24
+ "DeviceBusyError",
25
+ "DeviceInfo",
26
+ "FloatRange",
27
+ "Frame",
28
+ "GenICamError",
29
+ "GeneralError",
30
+ "GigEError",
31
+ "HikrobotError",
32
+ "IPConflictError",
33
+ "IncompleteImageError",
34
+ "InsufficientBufferError",
35
+ "IntRange",
36
+ "InvalidHandleError",
37
+ "NetworkError",
38
+ "NoDataError",
39
+ "NodeAccessError",
40
+ "NodeMap",
41
+ "NotImplementedByDeviceError",
42
+ "NotSupportedError",
43
+ "PacketError",
44
+ "ParameterError",
45
+ "PreconditionError",
46
+ "SDKLoadError",
47
+ "SDKNotFoundError",
48
+ "StatusError",
49
+ "TransportStats",
50
+ "USBBandwidthError",
51
+ "USBError",
52
+ "UnsupportedPixelFormatError",
53
+ "UnsupportedPlatformError",
54
+ "UpgradeError",
55
+ "ValueOutOfRangeError",
56
+ "__version__",
57
+ "enumerate_devices",
58
+ ]
59
+
60
+ from ._errors import (
61
+ AccessDeniedError,
62
+ BufferInUseError,
63
+ BufferReleasedError,
64
+ CallOrderError,
65
+ CameraStateError,
66
+ CameraTimeoutError,
67
+ DeviceBusyError,
68
+ GeneralError,
69
+ GenICamError,
70
+ GigEError,
71
+ HikrobotError,
72
+ IncompleteImageError,
73
+ InsufficientBufferError,
74
+ InvalidHandleError,
75
+ IPConflictError,
76
+ NetworkError,
77
+ NoDataError,
78
+ NodeAccessError,
79
+ NotImplementedByDeviceError,
80
+ NotSupportedError,
81
+ PacketError,
82
+ ParameterError,
83
+ PreconditionError,
84
+ SDKLoadError,
85
+ SDKNotFoundError,
86
+ StatusError,
87
+ UnsupportedPixelFormatError,
88
+ UnsupportedPlatformError,
89
+ UpgradeError,
90
+ USBBandwidthError,
91
+ USBError,
92
+ ValueOutOfRangeError,
93
+ )
94
+ from .camera import Camera, TransportStats
95
+ from .device import DeviceInfo, enumerate_devices
96
+ from .frame import Frame
97
+ from .nodes import FloatRange, IntRange, NodeMap
@@ -0,0 +1,568 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """ctypes transcription of the MVS structures needed to enumerate, open and grab.
3
+
4
+ Hand-written from the vendor C headers of MVS SDK 4.4.1 - ``CameraParams.h`` for the
5
+ structures and constants, ``MvCameraControl.h`` for the entry-point signatures. Only what
6
+ the enumerate/open/grab path needs is here; everything else is transcribed on demand.
7
+
8
+ Field names keep the vendor's spelling (``nWidth``, ``chSerialNumber``) so that a reader
9
+ can diff this file against the header line by line. Turning them into Python names is the
10
+ job of the public layer.
11
+
12
+ Three details that a careless transcription gets wrong:
13
+
14
+ * ``MvGvspPixelType`` contains ``PixelType_Gvsp_Undefined = 0xFFFFFFFF`` and a custom-format
15
+ bit of ``0x80000000``, so its values do not fit in a signed ``int``. The C enum is
16
+ therefore unsigned, and ``enPixelType`` must be read as :class:`ctypes.c_uint` - as a
17
+ signed field every custom 3D format would come back negative.
18
+ * ``MV_CC_DEVICE_INFO`` ends in a union of six transport-specific structures. Only the
19
+ GigE and USB3 members are ever read here, but every member has to be transcribed or the
20
+ union - and with it the whole device list - comes out the wrong size.
21
+ * The structures are naturally aligned, not packed. ``MV_FRAME_OUT_INFO_EX`` even carries
22
+ an explicit ``nReserved0`` whose header comment says it is there to 8-byte-align the
23
+ ``int64_t`` that follows, which confirms the vendor compiles with default alignment.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import ctypes
29
+ from ctypes import (
30
+ POINTER,
31
+ Structure,
32
+ Union,
33
+ c_bool,
34
+ c_char,
35
+ c_char_p,
36
+ c_float,
37
+ c_int,
38
+ c_int64,
39
+ c_ubyte,
40
+ c_uint,
41
+ c_uint64,
42
+ c_ushort,
43
+ c_void_p,
44
+ )
45
+ from typing import Any
46
+
47
+ from . import _loader
48
+
49
+ # --------------------------------------------------------------------------------------
50
+ # Constants (CameraParams.h)
51
+ # --------------------------------------------------------------------------------------
52
+
53
+ INFO_MAX_BUFFER_SIZE = 64
54
+ MV_MAX_DEVICE_NUM = 256
55
+
56
+ # Device transport layer protocol type, passed to MV_CC_EnumDevices as a bit mask.
57
+ MV_UNKNOW_DEVICE = 0x00000000
58
+ MV_GIGE_DEVICE = 0x00000001
59
+ MV_1394_DEVICE = 0x00000002
60
+ MV_USB_DEVICE = 0x00000004
61
+ MV_CAMERALINK_DEVICE = 0x00000008
62
+ MV_VIR_GIGE_DEVICE = 0x00000010
63
+ MV_VIR_USB_DEVICE = 0x00000020
64
+ MV_GENTL_GIGE_DEVICE = 0x00000040
65
+ MV_GENTL_CAMERALINK_DEVICE = 0x00000080
66
+ MV_GENTL_CXP_DEVICE = 0x00000100
67
+ MV_GENTL_XOF_DEVICE = 0x00000200
68
+
69
+ # Device access mode, passed to MV_CC_OpenDevice.
70
+ MV_ACCESS_Exclusive = 1
71
+ MV_ACCESS_ExclusiveWithSwitch = 2
72
+ MV_ACCESS_Control = 3
73
+ MV_ACCESS_ControlWithSwitch = 4
74
+ MV_ACCESS_ControlSwitchEnable = 5
75
+ MV_ACCESS_ControlSwitchEnableWithKey = 6
76
+ MV_ACCESS_Monitor = 7
77
+
78
+
79
+ # --------------------------------------------------------------------------------------
80
+ # Device information (CameraParams.h)
81
+ # --------------------------------------------------------------------------------------
82
+
83
+
84
+ class MV_GIGE_DEVICE_INFO(Structure):
85
+ """GigE Vision device information."""
86
+
87
+ _fields_ = [
88
+ ("nIpCfgOption", c_uint),
89
+ ("nIpCfgCurrent", c_uint),
90
+ ("nCurrentIp", c_uint),
91
+ ("nCurrentSubNetMask", c_uint),
92
+ ("nDefultGateWay", c_uint),
93
+ ("chManufacturerName", c_ubyte * 32),
94
+ ("chModelName", c_ubyte * 32),
95
+ ("chDeviceVersion", c_ubyte * 32),
96
+ ("chManufacturerSpecificInfo", c_ubyte * 48),
97
+ ("chSerialNumber", c_ubyte * 16),
98
+ ("chUserDefinedName", c_ubyte * 16),
99
+ ("nNetExport", c_uint),
100
+ ("nReserved", c_uint * 4),
101
+ ]
102
+
103
+
104
+ class MV_USB3_DEVICE_INFO(Structure):
105
+ """USB3 Vision device information."""
106
+
107
+ _fields_ = [
108
+ ("CrtlInEndPoint", c_ubyte),
109
+ ("CrtlOutEndPoint", c_ubyte),
110
+ ("StreamEndPoint", c_ubyte),
111
+ ("EventEndPoint", c_ubyte),
112
+ ("idVendor", c_ushort),
113
+ ("idProduct", c_ushort),
114
+ ("nDeviceNumber", c_uint),
115
+ ("chDeviceGUID", c_ubyte * INFO_MAX_BUFFER_SIZE),
116
+ ("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
117
+ ("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
118
+ ("chFamilyName", c_ubyte * INFO_MAX_BUFFER_SIZE),
119
+ ("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
120
+ ("chManufacturerName", c_ubyte * INFO_MAX_BUFFER_SIZE),
121
+ ("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
122
+ ("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
123
+ ("nbcdUSB", c_uint),
124
+ ("nDeviceAddress", c_uint),
125
+ ("nReserved", c_uint * 2),
126
+ ]
127
+
128
+
129
+ class MV_CamL_DEV_INFO(Structure):
130
+ """Camera Link device information."""
131
+
132
+ _fields_ = [
133
+ ("chPortID", c_ubyte * INFO_MAX_BUFFER_SIZE),
134
+ ("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
135
+ ("chFamilyName", c_ubyte * INFO_MAX_BUFFER_SIZE),
136
+ ("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
137
+ ("chManufacturerName", c_ubyte * INFO_MAX_BUFFER_SIZE),
138
+ ("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
139
+ ("nReserved", c_uint * 38),
140
+ ]
141
+
142
+
143
+ class MV_CXP_DEVICE_INFO(Structure):
144
+ """CoaXPress device information, as reported by a frame grabber."""
145
+
146
+ _fields_ = [
147
+ ("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
148
+ ("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
149
+ ("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
150
+ ("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
151
+ ("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
152
+ ("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
153
+ ("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
154
+ ("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
155
+ ("nReserved", c_uint * 7),
156
+ ]
157
+
158
+
159
+ class MV_CML_DEVICE_INFO(Structure):
160
+ """Camera Link device information, as reported by a frame grabber."""
161
+
162
+ _fields_ = [
163
+ ("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
164
+ ("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
165
+ ("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
166
+ ("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
167
+ ("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
168
+ ("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
169
+ ("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
170
+ ("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
171
+ ("nReserved", c_uint * 7),
172
+ ]
173
+
174
+
175
+ class MV_XOF_DEVICE_INFO(Structure):
176
+ """XoFLink device information, as reported by a frame grabber."""
177
+
178
+ _fields_ = [
179
+ ("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
180
+ ("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
181
+ ("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
182
+ ("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
183
+ ("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
184
+ ("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
185
+ ("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
186
+ ("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
187
+ ("nReserved", c_uint * 7),
188
+ ]
189
+
190
+
191
+ class _SpecialInfo(Union):
192
+ _fields_ = [
193
+ ("stGigEInfo", MV_GIGE_DEVICE_INFO),
194
+ ("stUsb3VInfo", MV_USB3_DEVICE_INFO),
195
+ ("stCamLInfo", MV_CamL_DEV_INFO),
196
+ ("stCMLInfo", MV_CML_DEVICE_INFO),
197
+ ("stCXPInfo", MV_CXP_DEVICE_INFO),
198
+ ("stXoFInfo", MV_XOF_DEVICE_INFO),
199
+ ]
200
+
201
+
202
+ class MV_CC_DEVICE_INFO(Structure):
203
+ """One enumerated device.
204
+
205
+ ``nTLayerType`` selects which member of ``SpecialInfo`` is the valid one; reading the
206
+ wrong member yields plausible-looking garbage rather than an error.
207
+ """
208
+
209
+ _fields_ = [
210
+ ("nMajorVer", c_ushort),
211
+ ("nMinorVer", c_ushort),
212
+ ("nMacAddrHigh", c_uint),
213
+ ("nMacAddrLow", c_uint),
214
+ ("nTLayerType", c_uint),
215
+ ("nDevTypeInfo", c_uint),
216
+ ("nReserved", c_uint * 3),
217
+ ("SpecialInfo", _SpecialInfo),
218
+ ]
219
+
220
+
221
+ class MV_CC_DEVICE_INFO_LIST(Structure):
222
+ """Result of ``MV_CC_EnumDevices``.
223
+
224
+ The SDK owns the pointed-to device structures. They stay valid only until the next
225
+ enumeration, so anything worth keeping must be copied out.
226
+ """
227
+
228
+ _fields_ = [
229
+ ("nDeviceNum", c_uint),
230
+ ("pDeviceInfo", POINTER(MV_CC_DEVICE_INFO) * MV_MAX_DEVICE_NUM),
231
+ ]
232
+
233
+
234
+ # --------------------------------------------------------------------------------------
235
+ # Frames (CameraParams.h)
236
+ # --------------------------------------------------------------------------------------
237
+
238
+
239
+ class _UnparsedChunkList(Union):
240
+ _fields_ = [
241
+ # MV_CHUNK_DATA_CONTENT*. Kept as an opaque pointer: chunk data is not parsed yet,
242
+ # and only the width of the member matters for the layout.
243
+ ("pUnparsedChunkContent", c_void_p),
244
+ ("nAligning", c_int64),
245
+ ]
246
+
247
+
248
+ class MV_FRAME_OUT_INFO_EX(Structure):
249
+ """Metadata of one grabbed frame.
250
+
251
+ ``nWidth`` / ``nHeight`` saturate at 65535; the header directs callers to
252
+ ``nExtendWidth`` / ``nExtendHeight`` above that. Likewise ``nFrameLen`` saturates at
253
+ 4 GiB and ``nFrameLenEx`` carries the real length.
254
+ """
255
+
256
+ _fields_ = [
257
+ ("nWidth", c_ushort),
258
+ ("nHeight", c_ushort),
259
+ # enum MvGvspPixelType - unsigned, see the module docstring.
260
+ ("enPixelType", c_uint),
261
+ ("nFrameNum", c_uint),
262
+ ("nDevTimeStampHigh", c_uint),
263
+ ("nDevTimeStampLow", c_uint),
264
+ ("nReserved0", c_uint),
265
+ ("nHostTimeStamp", c_int64),
266
+ ("nFrameLen", c_uint),
267
+ ("nSecondCount", c_uint),
268
+ ("nCycleCount", c_uint),
269
+ ("nCycleOffset", c_uint),
270
+ ("fGain", c_float),
271
+ ("fExposureTime", c_float),
272
+ ("nAverageBrightness", c_uint),
273
+ ("nRed", c_uint),
274
+ ("nGreen", c_uint),
275
+ ("nBlue", c_uint),
276
+ ("nFrameCounter", c_uint),
277
+ ("nTriggerIndex", c_uint),
278
+ ("nInput", c_uint),
279
+ ("nOutput", c_uint),
280
+ ("nOffsetX", c_ushort),
281
+ ("nOffsetY", c_ushort),
282
+ ("nChunkWidth", c_ushort),
283
+ ("nChunkHeight", c_ushort),
284
+ ("nLostPacket", c_uint),
285
+ ("nUnparsedChunkNum", c_uint),
286
+ ("UnparsedChunkList", _UnparsedChunkList),
287
+ ("nExtendWidth", c_uint),
288
+ ("nExtendHeight", c_uint),
289
+ ("nFrameLenEx", c_uint64),
290
+ ("nReserved", c_uint * 32),
291
+ ]
292
+
293
+
294
+ class MV_FRAME_OUT(Structure):
295
+ """A grabbed frame: a pointer into driver memory plus its metadata.
296
+
297
+ ``pBufAddr`` is a node from the SDK's fixed pool, not memory this process owns. It is
298
+ valid only until the node goes back with ``MV_CC_FreeImageBuffer``; after that the
299
+ driver writes the next frame to the same address.
300
+ """
301
+
302
+ _fields_ = [
303
+ ("pBufAddr", POINTER(c_ubyte)),
304
+ ("stFrameInfo", MV_FRAME_OUT_INFO_EX),
305
+ ("nRes", c_uint * 16),
306
+ ]
307
+
308
+
309
+ # --------------------------------------------------------------------------------------
310
+ # Pixel formats (PixelType.h)
311
+ # --------------------------------------------------------------------------------------
312
+ #
313
+ # A pixel type packs three fields: bits 24-31 say monochrome/colour/custom, bits 16-23 the
314
+ # effective bits per pixel including padding, bits 0-15 an arbitrary id. Only the last is
315
+ # opaque, so bit depth is computable while the channel layout is not - hence the explicit
316
+ # table in `frame.py`.
317
+
318
+ MV_GVSP_PIX_MONO = 0x01000000
319
+ MV_GVSP_PIX_COLOR = 0x02000000
320
+ MV_GVSP_PIX_CUSTOM = 0x80000000
321
+ MV_GVSP_PIX_COLOR_MASK = 0xFF000000
322
+ MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK = 0x00FF0000
323
+ MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT = 16
324
+ MV_GVSP_PIX_ID_MASK = 0x0000FFFF
325
+
326
+
327
+ def _pixel(color: int, bits: int, identifier: int) -> int:
328
+ """Compose a pixel type the way ``PixelType.h`` does."""
329
+ return color | (bits << MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT) | identifier
330
+
331
+
332
+ def pixel_bit_depth(pixel_type: int) -> int:
333
+ """Effective bits per pixel of a pixel type, padding included."""
334
+ return (pixel_type & MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK) >> (
335
+ MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT
336
+ )
337
+
338
+
339
+ PixelType_Gvsp_Undefined = 0xFFFFFFFF
340
+
341
+ PixelType_Gvsp_Mono8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0001)
342
+ PixelType_Gvsp_Mono10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0003)
343
+ PixelType_Gvsp_Mono10_Packed = _pixel(MV_GVSP_PIX_MONO, 12, 0x0004)
344
+ PixelType_Gvsp_Mono12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0005)
345
+ PixelType_Gvsp_Mono12_Packed = _pixel(MV_GVSP_PIX_MONO, 12, 0x0006)
346
+ PixelType_Gvsp_Mono14 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0025)
347
+ PixelType_Gvsp_Mono16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0007)
348
+
349
+ # Bayer data is undemosaiced, so the vendor tags it monochrome.
350
+ PixelType_Gvsp_BayerGR8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0008)
351
+ PixelType_Gvsp_BayerRG8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0009)
352
+ PixelType_Gvsp_BayerGB8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x000A)
353
+ PixelType_Gvsp_BayerBG8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x000B)
354
+ PixelType_Gvsp_BayerGR10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000C)
355
+ PixelType_Gvsp_BayerRG10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000D)
356
+ PixelType_Gvsp_BayerGB10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000E)
357
+ PixelType_Gvsp_BayerBG10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000F)
358
+ PixelType_Gvsp_BayerGR12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0010)
359
+ PixelType_Gvsp_BayerRG12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0011)
360
+ PixelType_Gvsp_BayerGB12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0012)
361
+ PixelType_Gvsp_BayerBG12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0013)
362
+ PixelType_Gvsp_BayerGR16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x002E)
363
+ PixelType_Gvsp_BayerRG16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x002F)
364
+ PixelType_Gvsp_BayerGB16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0030)
365
+ PixelType_Gvsp_BayerBG16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0031)
366
+
367
+ PixelType_Gvsp_RGB8_Packed = _pixel(MV_GVSP_PIX_COLOR, 24, 0x0014)
368
+ PixelType_Gvsp_BGR8_Packed = _pixel(MV_GVSP_PIX_COLOR, 24, 0x0015)
369
+ PixelType_Gvsp_RGBA8_Packed = _pixel(MV_GVSP_PIX_COLOR, 32, 0x0016)
370
+ PixelType_Gvsp_BGRA8_Packed = _pixel(MV_GVSP_PIX_COLOR, 32, 0x0017)
371
+
372
+
373
+ # --------------------------------------------------------------------------------------
374
+ # Node map values (CameraParams.h)
375
+ # --------------------------------------------------------------------------------------
376
+
377
+ MV_MAX_ENUM_SYMBOLIC_NUM = 256
378
+ MV_MAX_SYMBOLIC_LEN = 64
379
+
380
+
381
+ class MVCC_INTVALUE_EX(Structure):
382
+ """Current value and range of an integer node.
383
+
384
+ The non-``Ex`` form of this structure is 32-bit; GenICam integer nodes are 64-bit, so
385
+ only this one can carry values such as a full sensor timestamp.
386
+ """
387
+
388
+ _fields_ = [
389
+ ("nCurValue", c_int64),
390
+ ("nMax", c_int64),
391
+ ("nMin", c_int64),
392
+ ("nInc", c_int64),
393
+ ("nReserved", c_uint * 16),
394
+ ]
395
+
396
+
397
+ class MVCC_FLOATVALUE(Structure):
398
+ """Current value and range of a float node. There is no increment for these."""
399
+
400
+ _fields_ = [
401
+ ("fCurValue", c_float),
402
+ ("fMax", c_float),
403
+ ("fMin", c_float),
404
+ ("nReserved", c_uint * 4),
405
+ ]
406
+
407
+
408
+ class MVCC_ENUMVALUE_EX(Structure):
409
+ """Current value of an enumeration node and the raw values it accepts.
410
+
411
+ The entries are integers; ``MV_CC_GetEnumEntrySymbolic`` turns one into its name. The
412
+ non-``Ex`` form caps the list at 64, which some cameras' ``PixelFormat`` exceeds.
413
+ """
414
+
415
+ _fields_ = [
416
+ ("nCurValue", c_uint),
417
+ ("nSupportedNum", c_uint),
418
+ ("nSupportValue", c_uint * MV_MAX_ENUM_SYMBOLIC_NUM),
419
+ ("nReserved", c_uint * 4),
420
+ ]
421
+
422
+
423
+ class MVCC_ENUMENTRY(Structure):
424
+ """One entry of an enumeration: ``nValue`` goes in, ``chSymbolic`` comes back."""
425
+
426
+ _fields_ = [
427
+ ("nValue", c_uint),
428
+ ("chSymbolic", c_char * MV_MAX_SYMBOLIC_LEN),
429
+ ("nReserved", c_uint * 4),
430
+ ]
431
+
432
+
433
+ class MVCC_STRINGVALUE(Structure):
434
+ """Current value of a string node, with the length the node will accept."""
435
+
436
+ _fields_ = [
437
+ ("chCurValue", c_char * 256),
438
+ ("nMaxLength", c_int64),
439
+ ("nReserved", c_uint * 2),
440
+ ]
441
+
442
+
443
+ # --------------------------------------------------------------------------------------
444
+ # Transport statistics (CameraParams.h)
445
+ # --------------------------------------------------------------------------------------
446
+
447
+ MV_MATCH_TYPE_NET_DETECT = 0x00000001
448
+ MV_MATCH_TYPE_USB_DETECT = 0x00000002
449
+
450
+
451
+ class MV_MATCH_INFO_NET_DETECT(Structure):
452
+ """GigE traffic and packet-loss counters, accumulated between start and stop."""
453
+
454
+ _fields_ = [
455
+ ("nReceiveDataSize", c_int64),
456
+ ("nLostPacketCount", c_int64),
457
+ ("nLostFrameCount", c_uint),
458
+ ("nNetRecvFrameCount", c_uint),
459
+ ("nRequestResendPacketCount", c_int64),
460
+ ("nResendPacketCount", c_int64),
461
+ ]
462
+
463
+
464
+ class MV_MATCH_INFO_USB_DETECT(Structure):
465
+ """USB3 traffic counters, accumulated between open and close."""
466
+
467
+ _fields_ = [
468
+ ("nReceiveDataSize", c_int64),
469
+ ("nReceivedFrameCount", c_uint),
470
+ ("nErrorFrameCount", c_uint),
471
+ ("nReserved", c_uint * 2),
472
+ ]
473
+
474
+
475
+ class MV_ALL_MATCH_INFO(Structure):
476
+ """Request wrapper: ``nType`` selects the statistics, the caller owns the buffer."""
477
+
478
+ _fields_ = [
479
+ ("nType", c_uint),
480
+ ("pInfo", c_void_p),
481
+ ("nInfoSize", c_uint),
482
+ ]
483
+
484
+
485
+ # --------------------------------------------------------------------------------------
486
+ # Entry points (MvCameraControl.h)
487
+ # --------------------------------------------------------------------------------------
488
+
489
+ #: ``(symbol, argtypes, restype)``. Every entry point is declared before first use: an
490
+ #: unset ``argtypes`` happens to work on x86_64 Linux and corrupts the stack on Windows.
491
+ #: ``restype`` follows the header, which declares a signed ``int``; the checked-call helper
492
+ #: normalises it to unsigned before matching against the ``MV_E_*`` constants.
493
+ PROTOTYPES: tuple[tuple[str, list[Any], Any], ...] = (
494
+ ("MV_CC_GetSDKVersion", [], c_uint),
495
+ ("MV_CC_EnumDevices", [c_uint, POINTER(MV_CC_DEVICE_INFO_LIST)], c_int),
496
+ ("MV_CC_CreateHandle", [POINTER(c_void_p), POINTER(MV_CC_DEVICE_INFO)], c_int),
497
+ ("MV_CC_DestroyHandle", [c_void_p], c_int),
498
+ ("MV_CC_OpenDevice", [c_void_p, c_uint, c_ushort], c_int),
499
+ ("MV_CC_CloseDevice", [c_void_p], c_int),
500
+ ("MV_CC_IsDeviceConnected", [c_void_p], c_bool),
501
+ ("MV_CC_SetImageNodeNum", [c_void_p, c_uint], c_int),
502
+ ("MV_CC_StartGrabbing", [c_void_p], c_int),
503
+ ("MV_CC_StopGrabbing", [c_void_p], c_int),
504
+ ("MV_CC_GetImageBuffer", [c_void_p, POINTER(MV_FRAME_OUT), c_uint], c_int),
505
+ ("MV_CC_FreeImageBuffer", [c_void_p, POINTER(MV_FRAME_OUT)], c_int),
506
+ # Node map. Keys are GenICam node names, ASCII, e.g. b"ExposureTime".
507
+ ("MV_CC_GetIntValueEx", [c_void_p, c_char_p, POINTER(MVCC_INTVALUE_EX)], c_int),
508
+ ("MV_CC_SetIntValueEx", [c_void_p, c_char_p, c_int64], c_int),
509
+ ("MV_CC_GetFloatValue", [c_void_p, c_char_p, POINTER(MVCC_FLOATVALUE)], c_int),
510
+ ("MV_CC_SetFloatValue", [c_void_p, c_char_p, c_float], c_int),
511
+ ("MV_CC_GetBoolValue", [c_void_p, c_char_p, POINTER(c_bool)], c_int),
512
+ ("MV_CC_SetBoolValue", [c_void_p, c_char_p, c_bool], c_int),
513
+ ("MV_CC_GetEnumValueEx", [c_void_p, c_char_p, POINTER(MVCC_ENUMVALUE_EX)], c_int),
514
+ ("MV_CC_SetEnumValue", [c_void_p, c_char_p, c_uint], c_int),
515
+ ("MV_CC_SetEnumValueByString", [c_void_p, c_char_p, c_char_p], c_int),
516
+ ("MV_CC_GetEnumEntrySymbolic", [c_void_p, c_char_p, POINTER(MVCC_ENUMENTRY)], c_int),
517
+ ("MV_CC_GetStringValue", [c_void_p, c_char_p, POINTER(MVCC_STRINGVALUE)], c_int),
518
+ ("MV_CC_SetStringValue", [c_void_p, c_char_p, c_char_p], c_int),
519
+ ("MV_CC_SetCommandValue", [c_void_p, c_char_p], c_int),
520
+ # Transport tuning and statistics.
521
+ ("MV_CC_GetAllMatchInfo", [c_void_p, POINTER(MV_ALL_MATCH_INFO)], c_int),
522
+ # Returns the packet size itself, not a status - see `Camera.optimal_packet_size`.
523
+ ("MV_CC_GetOptimalPacketSize", [c_void_p], c_int),
524
+ ("MV_GIGE_SetResend", [c_void_p, c_uint, c_uint, c_uint], c_int),
525
+ )
526
+
527
+ _sdk: ctypes.CDLL | None = None
528
+
529
+
530
+ def apply_prototypes(lib: Any) -> None:
531
+ """Set ``argtypes`` and ``restype`` on every entry point this package calls.
532
+
533
+ Args:
534
+ lib: The loaded MVS library, or a test double standing in for it.
535
+
536
+ Raises:
537
+ AttributeError: The library does not export one of the expected symbols, which
538
+ means it is not the MVS library or is too old.
539
+ """
540
+ for symbol, argtypes, restype in PROTOTYPES:
541
+ func = getattr(lib, symbol)
542
+ func.argtypes = argtypes
543
+ func.restype = restype
544
+
545
+
546
+ def sdk() -> Any:
547
+ """Return the MVS library with every prototype declared, loading it on first call.
548
+
549
+ Raises:
550
+ SDKNotFoundError: The SDK is not installed or is installed somewhere unexpected.
551
+ SDKLoadError: The library was found but could not be opened.
552
+ UnsupportedPlatformError: The OS/CPU combination has no known SDK layout.
553
+ """
554
+ global _sdk
555
+ if _sdk is None:
556
+ lib = _loader.load()
557
+ apply_prototypes(lib)
558
+ _sdk = lib
559
+ return _sdk
560
+
561
+
562
+ def reset() -> None:
563
+ """Drop the cached library handle.
564
+
565
+ For tests only; the prototypes are reapplied on the next :func:`sdk` call.
566
+ """
567
+ global _sdk
568
+ _sdk = None