reader-integration-kit-linux-aarch64 1.4.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.
- reader_integration_kit/__init__.py +12 -0
- reader_integration_kit/enum/__init__.py +28 -0
- reader_integration_kit/enum/beep_duration.py +12 -0
- reader_integration_kit/enum/beep_volume.py +15 -0
- reader_integration_kit/enum/ble_data_type.py +12 -0
- reader_integration_kit/enum/blob_type.py +27 -0
- reader_integration_kit/enum/checkpoint_type.py +13 -0
- reader_integration_kit/enum/data_conversion_type.py +12 -0
- reader_integration_kit/enum/field_definition_type.py +14 -0
- reader_integration_kit/enum/led_color.py +15 -0
- reader_integration_kit/enum/protocol_type.py +14 -0
- reader_integration_kit/enum/proximity_card_type.py +166 -0
- reader_integration_kit/enum/reader_module_id.py +13 -0
- reader_integration_kit/enum/reader_module_state.py +12 -0
- reader_integration_kit/enum/serial_port_baud_rate.py +15 -0
- reader_integration_kit/enum/serial_port_data_bits.py +10 -0
- reader_integration_kit/enum/serial_port_flow_control.py +11 -0
- reader_integration_kit/enum/serial_port_parity.py +10 -0
- reader_integration_kit/enum/serial_port_stop_bits.py +9 -0
- reader_integration_kit/enum/transparent_mode_state.py +11 -0
- reader_integration_kit/enum/transparent_mode_status.py +11 -0
- reader_integration_kit/errors/__init__.py +4 -0
- reader_integration_kit/errors/reader_exception.py +58 -0
- reader_integration_kit/facade/__init__.py +852 -0
- reader_integration_kit/lib/libReaderIntegrationKit.so +0 -0
- reader_integration_kit/lib/libReaderIntegrationKit.so.1.4.0 +0 -0
- reader_integration_kit/structures/__init__.py +36 -0
- reader_integration_kit/structures/blob_header.py +54 -0
- reader_integration_kit/structures/bluetooth_firmware_version.py +35 -0
- reader_integration_kit/structures/card_data.py +77 -0
- reader_integration_kit/structures/card_type_info.py +51 -0
- reader_integration_kit/structures/device_id.py +12 -0
- reader_integration_kit/structures/extended_configuration.py +32 -0
- reader_integration_kit/structures/felica_sam_firmware_version.py +38 -0
- reader_integration_kit/structures/field_entry.py +120 -0
- reader_integration_kit/structures/field_separator_data_header.py +83 -0
- reader_integration_kit/structures/hash_data.py +55 -0
- reader_integration_kit/structures/hid_se_sam_firmware_version.py +38 -0
- reader_integration_kit/structures/led_configuration.py +13 -0
- reader_integration_kit/structures/library_info.py +74 -0
- reader_integration_kit/structures/luid_response_information.py +44 -0
- reader_integration_kit/structures/microcontroller_firmware_version.py +38 -0
- reader_integration_kit/structures/nxp_sam_firmware_version.py +38 -0
- reader_integration_kit/structures/reader_configuration.py +171 -0
- reader_integration_kit/structures/reader_data.py +49 -0
- reader_integration_kit/structures/reader_definition.py +14 -0
- reader_integration_kit/structures/reader_metadata_struct.py +195 -0
- reader_integration_kit/structures/rik_result.py +71 -0
- reader_integration_kit/structures/separator_character.py +44 -0
- reader_integration_kit/structures/separator_entry.py +73 -0
- reader_integration_kit/structures/serial_port_settings.py +45 -0
- reader_integration_kit/structures/smart_card_configuration.py +34 -0
- reader_integration_kit_linux_aarch64-1.4.0.dist-info/METADATA +115 -0
- reader_integration_kit_linux_aarch64-1.4.0.dist-info/RECORD +57 -0
- reader_integration_kit_linux_aarch64-1.4.0.dist-info/WHEEL +5 -0
- reader_integration_kit_linux_aarch64-1.4.0.dist-info/rfIDEAS_EULA.txt +281 -0
- reader_integration_kit_linux_aarch64-1.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Internal infrastructure module for loading the native library and managing function pointers.
|
|
3
|
+
This module is used internally by Reader and should not be used directly.
|
|
4
|
+
Use Reader instead for all reader operations.
|
|
5
|
+
"""
|
|
6
|
+
import ctypes
|
|
7
|
+
from ctypes import (
|
|
8
|
+
c_size_t, c_ushort, c_uint, c_byte, c_char_p, c_ulong, c_int, POINTER, Structure, byref,
|
|
9
|
+
create_string_buffer, c_void_p, c_uint8, c_uint16, c_uint32, c_bool, CFUNCTYPE
|
|
10
|
+
)
|
|
11
|
+
import os
|
|
12
|
+
import platform
|
|
13
|
+
from typing import Callable, Optional
|
|
14
|
+
|
|
15
|
+
# Type alias for the Python-level credential callback.
|
|
16
|
+
# Signature: callback(card_data: CardData) -> None
|
|
17
|
+
CredentialCallback = Callable[['CardData'], None]
|
|
18
|
+
|
|
19
|
+
from reader_integration_kit.errors import ReaderException
|
|
20
|
+
from reader_integration_kit.structures import *
|
|
21
|
+
from reader_integration_kit.enum import *
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _NativeLibrary:
|
|
25
|
+
"""Internal class for loading the native library and managing function pointers."""
|
|
26
|
+
|
|
27
|
+
_instance: Optional['_NativeLibrary'] = None
|
|
28
|
+
_native_library_handle = None
|
|
29
|
+
_dll = None
|
|
30
|
+
|
|
31
|
+
def __new__(cls):
|
|
32
|
+
if cls._instance is None:
|
|
33
|
+
cls._instance = super().__new__(cls)
|
|
34
|
+
cls._instance._load_library()
|
|
35
|
+
cls._instance._initialize_functions()
|
|
36
|
+
return cls._instance
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _get_library_name() -> str:
|
|
40
|
+
"""Get the library name based on the platform."""
|
|
41
|
+
if platform.system() == 'Windows':
|
|
42
|
+
return "ReaderIntegrationKit.dll"
|
|
43
|
+
elif platform.system() == 'Linux':
|
|
44
|
+
return "libReaderIntegrationKit.so"
|
|
45
|
+
elif platform.system() == 'Darwin':
|
|
46
|
+
return "libReaderIntegrationKit.dylib"
|
|
47
|
+
else:
|
|
48
|
+
raise RuntimeError(f"Unsupported OS platform: {platform.system()}")
|
|
49
|
+
|
|
50
|
+
def _get_library_path(self) -> str:
|
|
51
|
+
"""Get the path to the native library."""
|
|
52
|
+
library_name = self._get_library_name()
|
|
53
|
+
lib_dir = os.path.join(os.path.dirname(__file__), '..', 'lib')
|
|
54
|
+
lib_path = os.path.join(lib_dir, library_name)
|
|
55
|
+
|
|
56
|
+
if not os.path.exists(lib_path):
|
|
57
|
+
# Try alternative locations
|
|
58
|
+
alt_paths = [
|
|
59
|
+
os.path.join(os.path.dirname(__file__), '..', '..', 'lib', library_name),
|
|
60
|
+
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'lib', library_name),
|
|
61
|
+
library_name, # Try system library path
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
for alt_path in alt_paths:
|
|
65
|
+
if os.path.exists(alt_path):
|
|
66
|
+
return alt_path
|
|
67
|
+
|
|
68
|
+
raise FileNotFoundError(
|
|
69
|
+
f"Shared library not found. Tried: {lib_path} and {alt_paths}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return lib_path
|
|
73
|
+
|
|
74
|
+
def _load_library(self):
|
|
75
|
+
"""Load the native library."""
|
|
76
|
+
try:
|
|
77
|
+
lib_path = self._get_library_path()
|
|
78
|
+
# On Windows, use WinDLL to properly capture stdout/stderr from the DLL
|
|
79
|
+
# On Linux/Mac, use CDLL
|
|
80
|
+
if platform.system() == 'Windows':
|
|
81
|
+
self._dll = ctypes.WinDLL(lib_path)
|
|
82
|
+
else:
|
|
83
|
+
self._dll = ctypes.CDLL(lib_path)
|
|
84
|
+
self._native_library_handle = self._dll
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise RuntimeError(f"Failed to load native library: {e}") from e
|
|
87
|
+
|
|
88
|
+
def _initialize_functions(self):
|
|
89
|
+
"""Initialize all function signatures."""
|
|
90
|
+
# Factory functions
|
|
91
|
+
self._dll.RikReader_Open.argtypes = [POINTER(RikResult), POINTER(ReaderDefinition), c_int]
|
|
92
|
+
self._dll.RikReader_Open.restype = c_void_p
|
|
93
|
+
|
|
94
|
+
# Common reader methods
|
|
95
|
+
self._dll.Rik_Close.argtypes = [POINTER(RikResult), c_void_p]
|
|
96
|
+
self._dll.Rik_Close.restype = None
|
|
97
|
+
|
|
98
|
+
self._dll.Rik_Init.argtypes = [POINTER(RikResult), c_void_p]
|
|
99
|
+
self._dll.Rik_Init.restype = None
|
|
100
|
+
|
|
101
|
+
# Metadata functions - work directly with reader
|
|
102
|
+
self._dll.Rik_RefreshMetadata.argtypes = [POINTER(RikResult), c_void_p]
|
|
103
|
+
self._dll.Rik_RefreshMetadata.restype = None
|
|
104
|
+
|
|
105
|
+
# Rik_GetMetadataStruct
|
|
106
|
+
from reader_integration_kit.structures.reader_metadata_struct import ReaderMetadataStruct
|
|
107
|
+
self._dll.Rik_GetMetadataStruct.argtypes = [POINTER(RikResult), c_void_p, POINTER(ReaderMetadataStruct), c_bool]
|
|
108
|
+
self._dll.Rik_GetMetadataStruct.restype = None
|
|
109
|
+
|
|
110
|
+
# WaveID-specific methods
|
|
111
|
+
self._dll.RikReader_Beep.argtypes = [POINTER(RikResult), c_void_p, c_uint8, c_uint8]
|
|
112
|
+
self._dll.RikReader_Beep.restype = None
|
|
113
|
+
|
|
114
|
+
self._dll.RikReader_GetCardData.argtypes = [POINTER(RikResult), c_void_p, POINTER(c_uint8), ctypes.c_size_t, POINTER(ctypes.c_uint32)]
|
|
115
|
+
self._dll.RikReader_GetCardData.restype = None
|
|
116
|
+
|
|
117
|
+
self._dll.RikReader_GetBeeperVolume.argtypes = [POINTER(RikResult), c_void_p, POINTER(c_uint8)]
|
|
118
|
+
self._dll.RikReader_GetBeeperVolume.restype = None
|
|
119
|
+
|
|
120
|
+
self._dll.RikReader_SetBeeperVolume.argtypes = [POINTER(RikResult), c_void_p, c_uint8]
|
|
121
|
+
self._dll.RikReader_SetBeeperVolume.restype = None
|
|
122
|
+
|
|
123
|
+
self._dll.RikReader_GetReaderConfiguration.argtypes = [POINTER(RikResult), c_void_p, c_uint8, POINTER(ReaderConfigurationStruct), POINTER(ExtendedConfiguration)]
|
|
124
|
+
self._dll.RikReader_GetReaderConfiguration.restype = None
|
|
125
|
+
|
|
126
|
+
self._dll.RikReader_SetReaderConfiguration.argtypes = [POINTER(RikResult), c_void_p, c_uint8, POINTER(ReaderConfigurationStruct), POINTER(ExtendedConfiguration), POINTER(HashData)]
|
|
127
|
+
self._dll.RikReader_SetReaderConfiguration.restype = None
|
|
128
|
+
|
|
129
|
+
self._dll.RikReader_GetModuleState.argtypes = [POINTER(RikResult), c_void_p, c_uint8, POINTER(c_uint)]
|
|
130
|
+
self._dll.RikReader_GetModuleState.restype = None
|
|
131
|
+
|
|
132
|
+
self._dll.RikReader_SetModuleState.argtypes = [POINTER(RikResult), c_void_p, c_uint8, c_uint]
|
|
133
|
+
self._dll.RikReader_SetModuleState.restype = None
|
|
134
|
+
|
|
135
|
+
# LED configuration functions
|
|
136
|
+
from reader_integration_kit.structures.led_configuration import LedConfiguration
|
|
137
|
+
self._dll.RikReader_GetLedConfiguration.argtypes = [POINTER(RikResult), c_void_p, c_uint8, POINTER(LedConfiguration)]
|
|
138
|
+
self._dll.RikReader_GetLedConfiguration.restype = None
|
|
139
|
+
|
|
140
|
+
self._dll.RikReader_SetLedConfiguration.argtypes = [POINTER(RikResult), c_void_p, c_uint8, POINTER(LedConfiguration)]
|
|
141
|
+
self._dll.RikReader_SetLedConfiguration.restype = None
|
|
142
|
+
|
|
143
|
+
# Enable keystroking functions
|
|
144
|
+
self._dll.RikReader_EnableKeystroking.argtypes = [POINTER(RikResult), c_void_p, c_bool]
|
|
145
|
+
self._dll.RikReader_EnableKeystroking.restype = None
|
|
146
|
+
|
|
147
|
+
# LUID functions
|
|
148
|
+
self._dll.RikReader_GetLuid.argtypes = [POINTER(RikResult), c_void_p, POINTER(LuidResponseInformation)]
|
|
149
|
+
self._dll.RikReader_GetLuid.restype = None
|
|
150
|
+
|
|
151
|
+
self._dll.RikReader_SetLuid.argtypes = [POINTER(RikResult), c_void_p, c_uint16]
|
|
152
|
+
self._dll.RikReader_SetLuid.restype = None
|
|
153
|
+
|
|
154
|
+
# Get Supported Card Types
|
|
155
|
+
from reader_integration_kit.structures.card_type_info import SupportedCardTypesResult
|
|
156
|
+
self._dll.RikReader_GetSupportedCardTypes.argtypes = [POINTER(RikResult), c_void_p, POINTER(SupportedCardTypesResult)]
|
|
157
|
+
self._dll.RikReader_GetSupportedCardTypes.restype = None
|
|
158
|
+
|
|
159
|
+
# Read/Write BLE Configuration functions
|
|
160
|
+
self._dll.RikReader_ReadBleConfigurationFromReader.argtypes = [POINTER(RikResult), c_void_p, c_uint8, c_char_p]
|
|
161
|
+
self._dll.RikReader_ReadBleConfigurationFromReader.restype = None
|
|
162
|
+
|
|
163
|
+
self._dll.RikReader_WriteBleConfigurationToReader.argtypes = [POINTER(RikResult), c_void_p, c_uint8, c_char_p]
|
|
164
|
+
self._dll.RikReader_WriteBleConfigurationToReader.restype = None
|
|
165
|
+
|
|
166
|
+
# Hwg file functions
|
|
167
|
+
self._dll.RikReader_WriteHwgFileToReader.argtypes = [POINTER(RikResult), c_void_p, c_char_p]
|
|
168
|
+
self._dll.RikReader_WriteHwgFileToReader.restype = None
|
|
169
|
+
|
|
170
|
+
self._dll.RikReader_ReadHwgFileFromReader.argtypes = [POINTER(RikResult), c_void_p, c_char_p, c_bool]
|
|
171
|
+
self._dll.RikReader_ReadHwgFileFromReader.restype = None
|
|
172
|
+
|
|
173
|
+
# Smart card configuration functions
|
|
174
|
+
self._dll.RikReader_WriteSmartCardConfigurationToReader.argtypes = [POINTER(RikResult), c_void_p, c_char_p]
|
|
175
|
+
self._dll.RikReader_WriteSmartCardConfigurationToReader.restype = None
|
|
176
|
+
|
|
177
|
+
self._dll.RikReader_ReadSmartCardConfigurationFromReader.argtypes = [POINTER(RikResult), c_void_p, POINTER(SmartCardConfigurationStruct)]
|
|
178
|
+
self._dll.RikReader_ReadSmartCardConfigurationFromReader.restype = None
|
|
179
|
+
|
|
180
|
+
# Write and reset reader configuration functions
|
|
181
|
+
self._dll.RikReader_WriteUserDefaultsToReader.argtypes = [POINTER(RikResult), c_void_p]
|
|
182
|
+
self._dll.RikReader_WriteUserDefaultsToReader.restype = None
|
|
183
|
+
|
|
184
|
+
self._dll.RikReader_ResetReaderConfiguration.argtypes = [POINTER(RikResult), c_void_p, c_uint8]
|
|
185
|
+
self._dll.RikReader_ResetReaderConfiguration.restype = None
|
|
186
|
+
|
|
187
|
+
# Credential-presented callback functions
|
|
188
|
+
# NativeCredentialCallback: void (*)(const uint8_t* cardData, uint32_t bitCount)
|
|
189
|
+
NativeCredentialCallback = CFUNCTYPE(None, POINTER(c_uint8), c_uint32)
|
|
190
|
+
self._credential_callback_type = NativeCredentialCallback
|
|
191
|
+
self._dll.RikReader_OnCredentialPresented.argtypes = [POINTER(RikResult), c_void_p, NativeCredentialCallback]
|
|
192
|
+
self._dll.RikReader_OnCredentialPresented.restype = c_uint32
|
|
193
|
+
|
|
194
|
+
self._dll.RikReader_UnsubscribeCredentialCallback.argtypes = [POINTER(RikResult), c_void_p, c_uint32]
|
|
195
|
+
self._dll.RikReader_UnsubscribeCredentialCallback.restype = None
|
|
196
|
+
|
|
197
|
+
# Transparent mode functions
|
|
198
|
+
self._dll.RikReader_EnableTransparentMode.argtypes = [POINTER(RikResult), c_void_p, c_uint8, c_uint8]
|
|
199
|
+
self._dll.RikReader_EnableTransparentMode.restype = None
|
|
200
|
+
|
|
201
|
+
self._dll.RikReader_GetTransparentModeStatus.argtypes = [POINTER(RikResult), c_void_p, POINTER(c_uint8), POINTER(c_uint8)]
|
|
202
|
+
self._dll.RikReader_GetTransparentModeStatus.restype = None
|
|
203
|
+
|
|
204
|
+
# Library info function (extern "C")
|
|
205
|
+
from reader_integration_kit.structures.library_info import LibraryInfo
|
|
206
|
+
self._dll.Rik_BuildLibraryInfo.argtypes = []
|
|
207
|
+
self._dll.Rik_BuildLibraryInfo.restype = LibraryInfo
|
|
208
|
+
|
|
209
|
+
# Reader discovery functions
|
|
210
|
+
self._dll.Rik_DiscoverUsbReaders.argtypes = [POINTER(RikResult), POINTER(ReaderDefinition), POINTER(c_size_t)]
|
|
211
|
+
self._dll.Rik_DiscoverUsbReaders.restype = None
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class ReaderHandle:
|
|
215
|
+
"""Represents an opaque handle to an reader instance."""
|
|
216
|
+
|
|
217
|
+
def __init__(self, handle: c_void_p):
|
|
218
|
+
# Always store as c_void_p to guarantee correct type for is_valid comparison
|
|
219
|
+
self._handle = ctypes.c_void_p(handle if isinstance(handle, int) else getattr(handle, 'value', handle))
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def value(self) -> c_void_p:
|
|
223
|
+
"""Get the raw handle value."""
|
|
224
|
+
return self._handle
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def is_valid(self) -> bool:
|
|
228
|
+
"""Check if the handle is valid (not None/null)."""
|
|
229
|
+
return self._handle is not None and self._handle.value is not None
|
|
230
|
+
|
|
231
|
+
def __bool__(self) -> bool:
|
|
232
|
+
return self.is_valid
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class AbstractReader:
|
|
236
|
+
"""
|
|
237
|
+
Base class for Reader instances.
|
|
238
|
+
Provides common functionality for all reader types.
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
def __init__(self, handle: ReaderHandle, native_lib: _NativeLibrary):
|
|
242
|
+
"""
|
|
243
|
+
Initialize a new instance of the AbstractReader class.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
handle: The reader handle.
|
|
247
|
+
native_lib: The native library instance.
|
|
248
|
+
"""
|
|
249
|
+
self._native_lib = native_lib
|
|
250
|
+
self._handle: Optional[ReaderHandle] = handle
|
|
251
|
+
self._disposed = False
|
|
252
|
+
|
|
253
|
+
if not self._handle.is_valid:
|
|
254
|
+
raise RuntimeError("Failed to create reader instance: invalid handle")
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def handle(self) -> ReaderHandle:
|
|
258
|
+
"""Get the reader handle for this instance."""
|
|
259
|
+
return self._handle
|
|
260
|
+
|
|
261
|
+
def _throw_if_disposed(self):
|
|
262
|
+
"""Throw an exception if the object has been disposed."""
|
|
263
|
+
if self._disposed:
|
|
264
|
+
raise RuntimeError("AbstractReader instance has been disposed")
|
|
265
|
+
|
|
266
|
+
def __enter__(self):
|
|
267
|
+
"""Context manager entry."""
|
|
268
|
+
return self
|
|
269
|
+
|
|
270
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
271
|
+
"""Context manager exit - automatically dispose."""
|
|
272
|
+
self.dispose()
|
|
273
|
+
|
|
274
|
+
def dispose(self):
|
|
275
|
+
"""Dispose of the reader instance, destroying the native handle."""
|
|
276
|
+
if not self._disposed and self._handle is not None and self._handle.is_valid:
|
|
277
|
+
try:
|
|
278
|
+
# Unsubscribe all active credential callbacks before closing.
|
|
279
|
+
if hasattr(self, '_credential_callbacks'):
|
|
280
|
+
for sub_id in list(self._credential_callbacks.keys()):
|
|
281
|
+
try:
|
|
282
|
+
result = RikResult()
|
|
283
|
+
self._native_lib._dll.RikReader_UnsubscribeCredentialCallback(
|
|
284
|
+
byref(result), self._handle.value, c_uint32(sub_id))
|
|
285
|
+
except Exception:
|
|
286
|
+
pass
|
|
287
|
+
self._credential_callbacks.clear()
|
|
288
|
+
|
|
289
|
+
result = RikResult()
|
|
290
|
+
self._native_lib._dll.Rik_Close(byref(result), self._handle.value)
|
|
291
|
+
ReaderException.raise_if_error(result)
|
|
292
|
+
except Exception:
|
|
293
|
+
# Optionally log or handle native errors
|
|
294
|
+
pass
|
|
295
|
+
finally:
|
|
296
|
+
self._handle = None
|
|
297
|
+
self._disposed = True
|
|
298
|
+
|
|
299
|
+
def __del__(self):
|
|
300
|
+
"""Destructor - ensure cleanup."""
|
|
301
|
+
if hasattr(self, '_disposed') and not self._disposed:
|
|
302
|
+
self.dispose()
|
|
303
|
+
|
|
304
|
+
def init(self):
|
|
305
|
+
"""Initialize the reader (populates metadata, etc.)."""
|
|
306
|
+
self._throw_if_disposed()
|
|
307
|
+
result = RikResult()
|
|
308
|
+
self._native_lib._dll.Rik_Init(byref(result), self._handle.value)
|
|
309
|
+
ReaderException.raise_if_error(result)
|
|
310
|
+
|
|
311
|
+
def refresh_metadata(self):
|
|
312
|
+
"""Refresh metadata from device."""
|
|
313
|
+
self._throw_if_disposed()
|
|
314
|
+
result = RikResult()
|
|
315
|
+
self._native_lib._dll.Rik_RefreshMetadata(byref(result), self._handle.value)
|
|
316
|
+
ReaderException.raise_if_error(result)
|
|
317
|
+
|
|
318
|
+
def get_metadata(self, force_refresh: bool = False) -> dict:
|
|
319
|
+
"""
|
|
320
|
+
Get metadata as a dictionary.
|
|
321
|
+
Returns a fully populated dictionary with all available metadata fields.
|
|
322
|
+
Only fields that are present (Has* flag is True) will be included.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
force_refresh: If True, forces a refresh from the device even if metadata
|
|
326
|
+
has already been populated. If False (default), metadata is
|
|
327
|
+
populated lazily on first access.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Dictionary containing all available metadata fields.
|
|
331
|
+
"""
|
|
332
|
+
self._throw_if_disposed()
|
|
333
|
+
from reader_integration_kit.structures.reader_metadata_struct import ReaderMetadataStruct
|
|
334
|
+
|
|
335
|
+
# Create the struct to receive the data
|
|
336
|
+
metadata_struct = ReaderMetadataStruct()
|
|
337
|
+
|
|
338
|
+
# Call the native function to populate the struct
|
|
339
|
+
result = RikResult()
|
|
340
|
+
self._native_lib._dll.Rik_GetMetadataStruct(byref(result), self._handle.value, byref(metadata_struct), force_refresh)
|
|
341
|
+
ReaderException.raise_if_error(result)
|
|
342
|
+
|
|
343
|
+
# Convert the struct to a dictionary
|
|
344
|
+
return metadata_struct.to_dict()
|
|
345
|
+
|
|
346
|
+
@staticmethod
|
|
347
|
+
def get_library_info() -> dict:
|
|
348
|
+
"""
|
|
349
|
+
Get library information including version and build metadata.
|
|
350
|
+
This is a static method that does not require an reader instance.
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Dictionary containing library information (name, version, build date, etc.).
|
|
354
|
+
"""
|
|
355
|
+
from reader_integration_kit.structures.library_info import LibraryInfo
|
|
356
|
+
|
|
357
|
+
# Get the native library instance to access the DLL
|
|
358
|
+
native_lib = _NativeLibrary()
|
|
359
|
+
|
|
360
|
+
# Call Rik_BuildLibraryInfo (extern "C" function)
|
|
361
|
+
library_info = native_lib._dll.Rik_BuildLibraryInfo()
|
|
362
|
+
|
|
363
|
+
# Convert to dictionary
|
|
364
|
+
return library_info.to_dict()
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class Reader(AbstractReader):
|
|
368
|
+
"""
|
|
369
|
+
A class that encapsulates a WaveID reader handle and provides instance methods for WaveID operations.
|
|
370
|
+
The handle is automatically created in the constructor and destroyed when the object is disposed.
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
def __init__(self, reader_definition: ReaderDefinition, retry_count: int = 3):
|
|
374
|
+
"""
|
|
375
|
+
Initialize a new instance of the Reader class with the specified reader definition.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
reader_definition: The reader definition to use for creating the reader instance.
|
|
379
|
+
retry_count: The number of retries to attempt when creating the reader instance. Default is 3.
|
|
380
|
+
"""
|
|
381
|
+
native_lib = _NativeLibrary()
|
|
382
|
+
|
|
383
|
+
# Create reader handle
|
|
384
|
+
result = RikResult()
|
|
385
|
+
handle_ptr = native_lib._dll.RikReader_Open(
|
|
386
|
+
byref(result), byref(reader_definition), c_int(retry_count)
|
|
387
|
+
)
|
|
388
|
+
ReaderException.raise_if_error(result)
|
|
389
|
+
|
|
390
|
+
if handle_ptr is None:
|
|
391
|
+
raise RuntimeError("Failed to create WaveID reader instance: returned None")
|
|
392
|
+
|
|
393
|
+
handle = ReaderHandle(handle_ptr)
|
|
394
|
+
|
|
395
|
+
self._credential_callbacks = {}
|
|
396
|
+
super().__init__(handle, native_lib)
|
|
397
|
+
|
|
398
|
+
def beep(self, beep_count: int, duration: BeepDuration) -> None:
|
|
399
|
+
"""Beep the reader."""
|
|
400
|
+
self._throw_if_disposed()
|
|
401
|
+
duration_value = duration.value if hasattr(duration, 'value') else duration
|
|
402
|
+
result = RikResult()
|
|
403
|
+
self._native_lib._dll.RikReader_Beep(
|
|
404
|
+
byref(result), self._handle.value, c_uint8(beep_count), c_uint8(duration_value)
|
|
405
|
+
)
|
|
406
|
+
ReaderException.raise_if_error(result)
|
|
407
|
+
|
|
408
|
+
def get_beeper_volume(self) -> BeepVolume:
|
|
409
|
+
"""Get the beeper volume."""
|
|
410
|
+
self._throw_if_disposed()
|
|
411
|
+
volume = c_uint8()
|
|
412
|
+
result = RikResult()
|
|
413
|
+
self._native_lib._dll.RikReader_GetBeeperVolume(
|
|
414
|
+
byref(result), self._handle.value, byref(volume)
|
|
415
|
+
)
|
|
416
|
+
ReaderException.raise_if_error(result)
|
|
417
|
+
return BeepVolume(volume.value)
|
|
418
|
+
|
|
419
|
+
def set_beeper_volume(self, volume: BeepVolume) -> None:
|
|
420
|
+
"""Set the beeper volume."""
|
|
421
|
+
self._throw_if_disposed()
|
|
422
|
+
volume_value = volume.value if hasattr(volume, 'value') else volume
|
|
423
|
+
result = RikResult()
|
|
424
|
+
self._native_lib._dll.RikReader_SetBeeperVolume(
|
|
425
|
+
byref(result), self._handle.value, c_uint8(volume_value)
|
|
426
|
+
)
|
|
427
|
+
ReaderException.raise_if_error(result)
|
|
428
|
+
|
|
429
|
+
def get_module_state(self, module_id: ReaderModuleId) -> ReaderModuleState:
|
|
430
|
+
"""
|
|
431
|
+
Get the module state for the specified module.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
module_id: The module ID to query.
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
The current state of the specified module.
|
|
438
|
+
"""
|
|
439
|
+
self._throw_if_disposed()
|
|
440
|
+
module_id_value = module_id.value if hasattr(module_id, 'value') else module_id
|
|
441
|
+
state = c_uint()
|
|
442
|
+
result = RikResult()
|
|
443
|
+
self._native_lib._dll.RikReader_GetModuleState(
|
|
444
|
+
byref(result), self._handle.value, c_uint8(module_id_value), byref(state)
|
|
445
|
+
)
|
|
446
|
+
ReaderException.raise_if_error(result)
|
|
447
|
+
|
|
448
|
+
# Try to convert to enum, but handle unexpected values gracefully
|
|
449
|
+
try:
|
|
450
|
+
return ReaderModuleState(state.value)
|
|
451
|
+
except ValueError:
|
|
452
|
+
# If the value isn't in the enum, raise a more helpful error
|
|
453
|
+
raise ValueError(
|
|
454
|
+
f"Received unexpected module state value: {state.value} (0x{state.value:X}). "
|
|
455
|
+
f"Valid values are: {[f'{s.name}={s.value} (0x{s.value:X})' for s in ReaderModuleState]}"
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
def set_module_state(self, module_id: ReaderModuleId, state: ReaderModuleState) -> None:
|
|
459
|
+
"""
|
|
460
|
+
Set the module state for the specified module.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
module_id: The module ID to configure.
|
|
464
|
+
state: The desired state for the module.
|
|
465
|
+
"""
|
|
466
|
+
self._throw_if_disposed()
|
|
467
|
+
module_id_value = module_id.value if hasattr(module_id, 'value') else module_id
|
|
468
|
+
state_value = state.value if hasattr(state, 'value') else state
|
|
469
|
+
result = RikResult()
|
|
470
|
+
self._native_lib._dll.RikReader_SetModuleState(
|
|
471
|
+
byref(result), self._handle.value, c_uint8(module_id_value), c_uint(state_value)
|
|
472
|
+
)
|
|
473
|
+
ReaderException.raise_if_error(result)
|
|
474
|
+
|
|
475
|
+
def get_card_data(self) -> 'CardData':
|
|
476
|
+
"""
|
|
477
|
+
Get card data from the reader.
|
|
478
|
+
Returns:
|
|
479
|
+
CardData: The card data read from the reader.
|
|
480
|
+
Raises:
|
|
481
|
+
ReaderException: If the operation fails or no valid card data is available.
|
|
482
|
+
"""
|
|
483
|
+
self._throw_if_disposed()
|
|
484
|
+
from reader_integration_kit.structures.card_data import CardData
|
|
485
|
+
|
|
486
|
+
# Allocate buffer for card data (32 bytes)
|
|
487
|
+
buffer = (ctypes.c_uint8 * 32)()
|
|
488
|
+
bit_count = ctypes.c_uint32()
|
|
489
|
+
result = RikResult()
|
|
490
|
+
self._native_lib._dll.RikReader_GetCardData(
|
|
491
|
+
byref(result), self._handle.value, buffer, ctypes.c_size_t(32), byref(bit_count)
|
|
492
|
+
)
|
|
493
|
+
ReaderException.raise_if_error(result)
|
|
494
|
+
# Create CardData and populate it
|
|
495
|
+
card_data = CardData()
|
|
496
|
+
for i in range(32):
|
|
497
|
+
card_data.data[i] = buffer[i]
|
|
498
|
+
card_data.bit_count = bit_count.value
|
|
499
|
+
return card_data
|
|
500
|
+
|
|
501
|
+
def get_reader_configuration(self, configuration_number: int) -> tuple[ReaderConfigurationStruct, ExtendedConfiguration]:
|
|
502
|
+
"""Get the WaveID reader configuration and Extended configuration for the specified configuration number."""
|
|
503
|
+
self._throw_if_disposed()
|
|
504
|
+
config = ReaderConfigurationStruct()
|
|
505
|
+
extended_config = ExtendedConfiguration()
|
|
506
|
+
result = RikResult()
|
|
507
|
+
self._native_lib._dll.RikReader_GetReaderConfiguration(
|
|
508
|
+
byref(result), self._handle.value, c_uint8(configuration_number), byref(config), byref(extended_config)
|
|
509
|
+
)
|
|
510
|
+
ReaderException.raise_if_error(result)
|
|
511
|
+
return config, extended_config
|
|
512
|
+
|
|
513
|
+
def set_reader_configuration(self, configuration_number: int, config: ReaderConfigurationStruct, extended_config: ExtendedConfiguration, hash_data: HashData) -> None:
|
|
514
|
+
"""Set the WaveID reader configuration and Extended configuration for the specified configuration number."""
|
|
515
|
+
self._throw_if_disposed()
|
|
516
|
+
result = RikResult()
|
|
517
|
+
self._native_lib._dll.RikReader_SetReaderConfiguration(
|
|
518
|
+
byref(result), self._handle.value, c_uint8(configuration_number), byref(config), byref(extended_config), byref(hash_data)
|
|
519
|
+
)
|
|
520
|
+
ReaderException.raise_if_error(result)
|
|
521
|
+
|
|
522
|
+
def get_led_configuration(self, configuration_number: int):
|
|
523
|
+
"""Get the LED configuration for the specified configuration number."""
|
|
524
|
+
self._throw_if_disposed()
|
|
525
|
+
from reader_integration_kit.structures.led_configuration import LedConfiguration
|
|
526
|
+
led_config = LedConfiguration()
|
|
527
|
+
result = RikResult()
|
|
528
|
+
self._native_lib._dll.RikReader_GetLedConfiguration(
|
|
529
|
+
byref(result), self._handle.value, c_uint8(configuration_number), byref(led_config)
|
|
530
|
+
)
|
|
531
|
+
ReaderException.raise_if_error(result)
|
|
532
|
+
return led_config
|
|
533
|
+
|
|
534
|
+
def set_led_configuration(self, configuration_number: int, led_configuration):
|
|
535
|
+
"""Set the LED configuration for the specified configuration number."""
|
|
536
|
+
self._throw_if_disposed()
|
|
537
|
+
result = RikResult()
|
|
538
|
+
self._native_lib._dll.RikReader_SetLedConfiguration(
|
|
539
|
+
byref(result), self._handle.value, c_uint8(configuration_number), byref(led_configuration)
|
|
540
|
+
)
|
|
541
|
+
ReaderException.raise_if_error(result)
|
|
542
|
+
|
|
543
|
+
def enable_keystroking(self, enable: bool) -> None:
|
|
544
|
+
"""Enable or disable key stroking."""
|
|
545
|
+
self._throw_if_disposed()
|
|
546
|
+
result = RikResult()
|
|
547
|
+
self._native_lib._dll.RikReader_EnableKeystroking(
|
|
548
|
+
byref(result), self._handle.value, c_bool(enable)
|
|
549
|
+
)
|
|
550
|
+
ReaderException.raise_if_error(result)
|
|
551
|
+
|
|
552
|
+
def get_luid(self) -> LuidResponseInformation:
|
|
553
|
+
"""
|
|
554
|
+
Get Luid information from the reader.
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
557
|
+
LuidResponseInformation: Structure containing Luid, application version, and bootloader version.
|
|
558
|
+
"""
|
|
559
|
+
self._throw_if_disposed()
|
|
560
|
+
luid_info = LuidResponseInformation()
|
|
561
|
+
result = RikResult()
|
|
562
|
+
self._native_lib._dll.RikReader_GetLuid(
|
|
563
|
+
byref(result), self._handle.value, byref(luid_info)
|
|
564
|
+
)
|
|
565
|
+
ReaderException.raise_if_error(result)
|
|
566
|
+
return luid_info
|
|
567
|
+
|
|
568
|
+
def set_luid(self, luid: int) -> None:
|
|
569
|
+
"""
|
|
570
|
+
Set Luid on the reader.
|
|
571
|
+
|
|
572
|
+
Args:
|
|
573
|
+
luid: The Luid value to set.
|
|
574
|
+
"""
|
|
575
|
+
self._throw_if_disposed()
|
|
576
|
+
result = RikResult()
|
|
577
|
+
self._native_lib._dll.RikReader_SetLuid(
|
|
578
|
+
byref(result), self._handle.value, c_uint16(luid)
|
|
579
|
+
)
|
|
580
|
+
ReaderException.raise_if_error(result)
|
|
581
|
+
|
|
582
|
+
def write_user_defaults_to_reader(self) -> None:
|
|
583
|
+
"""Write user defaults to reader (copies active flash configuration to stored flash)."""
|
|
584
|
+
self._throw_if_disposed()
|
|
585
|
+
result = RikResult()
|
|
586
|
+
self._native_lib._dll.RikReader_WriteUserDefaultsToReader(
|
|
587
|
+
byref(result), self._handle.value
|
|
588
|
+
)
|
|
589
|
+
ReaderException.raise_if_error(result)
|
|
590
|
+
|
|
591
|
+
def reset_reader_configuration(self, checkpoint_type: CheckpointType) -> None:
|
|
592
|
+
"""
|
|
593
|
+
Reset reader configuration to a specified checkpoint.
|
|
594
|
+
|
|
595
|
+
Args:
|
|
596
|
+
checkpoint_type: CheckpointType enum value (FACTORY_DEFAULTS=1, USER_SETTINGS=2).
|
|
597
|
+
"""
|
|
598
|
+
self._throw_if_disposed()
|
|
599
|
+
result = RikResult()
|
|
600
|
+
self._native_lib._dll.RikReader_ResetReaderConfiguration(
|
|
601
|
+
byref(result), self._handle.value, c_uint8(checkpoint_type.value)
|
|
602
|
+
)
|
|
603
|
+
ReaderException.raise_if_error(result)
|
|
604
|
+
|
|
605
|
+
def get_supported_card_types(self) -> list:
|
|
606
|
+
"""Get the supported card types for this reader.
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
list: A list of CardTypeInfo dicts, each containing 'Value', 'Name', and 'EnumName'.
|
|
610
|
+
"""
|
|
611
|
+
self._throw_if_disposed()
|
|
612
|
+
from reader_integration_kit.structures.card_type_info import SupportedCardTypesResult
|
|
613
|
+
|
|
614
|
+
result = RikResult()
|
|
615
|
+
supported = SupportedCardTypesResult()
|
|
616
|
+
|
|
617
|
+
self._native_lib._dll.RikReader_GetSupportedCardTypes(
|
|
618
|
+
byref(result), self._handle.value, byref(supported)
|
|
619
|
+
)
|
|
620
|
+
ReaderException.raise_if_error(result)
|
|
621
|
+
|
|
622
|
+
# Convert valid entries to dicts
|
|
623
|
+
return [supported.CardTypes[i].to_dict() for i in range(supported.Count)]
|
|
624
|
+
|
|
625
|
+
def read_ble_configuration_from_reader(self, data_type: BleDataType, file_name: str) -> None:
|
|
626
|
+
"""
|
|
627
|
+
Read BLE configuration from the reader and write it to a file.
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
data_type: The BLE data type (BleDataType.DATA or BleDataType.KEY).
|
|
631
|
+
file_name: The file path to write the BLE configuration to.
|
|
632
|
+
The file will be in BLE HWG+ format (.hwg+ extension recommended).
|
|
633
|
+
|
|
634
|
+
Raises:
|
|
635
|
+
ReaderException: If the operation fails.
|
|
636
|
+
"""
|
|
637
|
+
self._throw_if_disposed()
|
|
638
|
+
data_type_value = data_type.value if hasattr(data_type, 'value') else data_type
|
|
639
|
+
|
|
640
|
+
result = RikResult()
|
|
641
|
+
file_name_bytes = file_name.encode('utf-8')
|
|
642
|
+
|
|
643
|
+
self._native_lib._dll.RikReader_ReadBleConfigurationFromReader(
|
|
644
|
+
byref(result), self._handle.value, c_uint8(data_type_value), file_name_bytes
|
|
645
|
+
)
|
|
646
|
+
ReaderException.raise_if_error(result)
|
|
647
|
+
|
|
648
|
+
def write_ble_configuration_to_reader(self, data_type: BleDataType, file_name: str) -> None:
|
|
649
|
+
"""
|
|
650
|
+
Write BLE configuration from a file to the reader.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
data_type: The BLE data type (BleDataType.DATA, BleDataType.KEY, or BleDataType.UNENCRYPTED_KEY).
|
|
654
|
+
file_name: The file path to read the BLE configuration from.
|
|
655
|
+
The file must be in BLE HWG+ format (.hwg+ extension).
|
|
656
|
+
|
|
657
|
+
Raises:
|
|
658
|
+
ReaderException: If the operation fails.
|
|
659
|
+
"""
|
|
660
|
+
self._throw_if_disposed()
|
|
661
|
+
data_type_value = data_type.value if hasattr(data_type, 'value') else data_type
|
|
662
|
+
|
|
663
|
+
result = RikResult()
|
|
664
|
+
file_name_bytes = file_name.encode('utf-8')
|
|
665
|
+
|
|
666
|
+
self._native_lib._dll.RikReader_WriteBleConfigurationToReader(
|
|
667
|
+
byref(result), self._handle.value, c_uint8(data_type_value), file_name_bytes
|
|
668
|
+
)
|
|
669
|
+
ReaderException.raise_if_error(result)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def write_hwg_file_to_reader(self, file_name: str) -> None:
|
|
673
|
+
"""Write an HWG file to the WaveID reader."""
|
|
674
|
+
self._throw_if_disposed()
|
|
675
|
+
result = RikResult()
|
|
676
|
+
self._native_lib._dll.RikReader_WriteHwgFileToReader(
|
|
677
|
+
byref(result), self._handle.value, c_char_p(file_name.encode('utf-8'))
|
|
678
|
+
)
|
|
679
|
+
ReaderException.raise_if_error(result)
|
|
680
|
+
|
|
681
|
+
def read_hwg_file_from_reader(self, file_name: str, secure_hwg_format: bool = True) -> None:
|
|
682
|
+
"""Read an HWG file from the WaveID reader."""
|
|
683
|
+
self._throw_if_disposed()
|
|
684
|
+
result = RikResult()
|
|
685
|
+
self._native_lib._dll.RikReader_ReadHwgFileFromReader(
|
|
686
|
+
byref(result), self._handle.value, c_char_p(file_name.encode('utf-8')), c_bool(secure_hwg_format)
|
|
687
|
+
)
|
|
688
|
+
ReaderException.raise_if_error(result)
|
|
689
|
+
|
|
690
|
+
def write_smart_card_configuration_to_reader(self, file_name: str) -> None:
|
|
691
|
+
"""Write smart card configuration to the reader."""
|
|
692
|
+
self._throw_if_disposed()
|
|
693
|
+
result = RikResult()
|
|
694
|
+
self._native_lib._dll.RikReader_WriteSmartCardConfigurationToReader(
|
|
695
|
+
byref(result), self._handle.value, file_name.encode('utf-8')
|
|
696
|
+
)
|
|
697
|
+
ReaderException.raise_if_error(result)
|
|
698
|
+
|
|
699
|
+
def read_smart_card_configuration_from_reader(self, config: SmartCardConfigurationStruct) -> None:
|
|
700
|
+
"""Read smart card configuration from the reader."""
|
|
701
|
+
self._throw_if_disposed()
|
|
702
|
+
result = RikResult()
|
|
703
|
+
self._native_lib._dll.RikReader_ReadSmartCardConfigurationFromReader(
|
|
704
|
+
byref(result), self._handle.value, byref(config)
|
|
705
|
+
)
|
|
706
|
+
ReaderException.raise_if_error(result)
|
|
707
|
+
|
|
708
|
+
def on_credential_presented(self, callback: CredentialCallback) -> int:
|
|
709
|
+
"""
|
|
710
|
+
Subscribe to card-read events. The callback is invoked on the reader's
|
|
711
|
+
background executor thread whenever a new credential is detected.
|
|
712
|
+
|
|
713
|
+
The event fires on the leading edge of a card presence. If a card remains
|
|
714
|
+
on the reader continuously - including across periods with no active
|
|
715
|
+
subscribers - the event will not re-fire for that card. The event only
|
|
716
|
+
fires again after the card is removed and a new (or the same) card is
|
|
717
|
+
presented.
|
|
718
|
+
|
|
719
|
+
Note:
|
|
720
|
+
If a card is removed and re-placed while no subscribers are active,this may not be detected.
|
|
721
|
+
|
|
722
|
+
Args:
|
|
723
|
+
callback: A Python callable with signature
|
|
724
|
+
``callback(card_data: CardData) -> None``.
|
|
725
|
+
The callable is kept alive automatically for the duration
|
|
726
|
+
of the subscription.
|
|
727
|
+
|
|
728
|
+
Returns:
|
|
729
|
+
int: A subscription ID. Pass this to unsubscribe_credential_callback()
|
|
730
|
+
to cancel the subscription.
|
|
731
|
+
"""
|
|
732
|
+
self._throw_if_disposed()
|
|
733
|
+
|
|
734
|
+
# Build the CFUNCTYPE wrapper and keep it alive on self to prevent GC.
|
|
735
|
+
NativeCredentialCallback = self._native_lib._credential_callback_type
|
|
736
|
+
|
|
737
|
+
def _native_cb(card_data_ptr, bit_count):
|
|
738
|
+
card_data = CardData()
|
|
739
|
+
for i in range(len(card_data.data)):
|
|
740
|
+
card_data.data[i] = card_data_ptr[i]
|
|
741
|
+
card_data.bit_count = bit_count
|
|
742
|
+
callback(card_data)
|
|
743
|
+
|
|
744
|
+
native_cb = NativeCredentialCallback(_native_cb)
|
|
745
|
+
|
|
746
|
+
# Store against subscription ID after we know the ID.
|
|
747
|
+
result = RikResult()
|
|
748
|
+
sub_id = self._native_lib._dll.RikReader_OnCredentialPresented(
|
|
749
|
+
byref(result), self._handle.value, native_cb
|
|
750
|
+
)
|
|
751
|
+
ReaderException.raise_if_error(result)
|
|
752
|
+
|
|
753
|
+
# Keep the ctypes wrapper alive for the duration of the subscription.
|
|
754
|
+
self._credential_callbacks[sub_id] = native_cb
|
|
755
|
+
|
|
756
|
+
return sub_id
|
|
757
|
+
|
|
758
|
+
def unsubscribe_credential_callback(self, subscription_id: int) -> None:
|
|
759
|
+
"""
|
|
760
|
+
Cancel a previously registered credential-callback subscription.
|
|
761
|
+
Stops the polling thread if no subscribers remain.
|
|
762
|
+
|
|
763
|
+
Args:
|
|
764
|
+
subscription_id: The ID previously returned by on_credential_presented().
|
|
765
|
+
"""
|
|
766
|
+
self._throw_if_disposed()
|
|
767
|
+
result = RikResult()
|
|
768
|
+
self._native_lib._dll.RikReader_UnsubscribeCredentialCallback(
|
|
769
|
+
byref(result), self._handle.value, c_uint32(subscription_id)
|
|
770
|
+
)
|
|
771
|
+
ReaderException.raise_if_error(result)
|
|
772
|
+
|
|
773
|
+
# Release the ctypes wrapper now that the C++ side no longer holds it.
|
|
774
|
+
self._credential_callbacks.pop(subscription_id, None)
|
|
775
|
+
|
|
776
|
+
def enable_transparent_mode(self, enable: bool, write_to_flash: bool) -> None:
|
|
777
|
+
"""Enable or disable transparent mode on the reader.
|
|
778
|
+
|
|
779
|
+
Args:
|
|
780
|
+
enable: True to enable transparent mode, False to disable.
|
|
781
|
+
write_to_flash: True for permanently enabling/disabling the transparent mode state irrespective of the reader power cycle. False otherwise.
|
|
782
|
+
"""
|
|
783
|
+
self._throw_if_disposed()
|
|
784
|
+
result = RikResult()
|
|
785
|
+
self._native_lib._dll.RikReader_EnableTransparentMode(
|
|
786
|
+
byref(result), self._handle.value,
|
|
787
|
+
c_uint8(1 if enable else 0),
|
|
788
|
+
c_uint8(1 if write_to_flash else 0)
|
|
789
|
+
)
|
|
790
|
+
ReaderException.raise_if_error(result)
|
|
791
|
+
|
|
792
|
+
def get_transparent_mode_status(self) -> tuple[TransparentModeState, TransparentModeStatus]:
|
|
793
|
+
"""
|
|
794
|
+
Get the current transparent mode state and status from the reader.
|
|
795
|
+
|
|
796
|
+
Returns:
|
|
797
|
+
tuple:
|
|
798
|
+
TransparentModeState indicates whether transparent mode is currently enabled or disabled in the reader. <br>
|
|
799
|
+
TransparentModeStatus Can be Ready/NotReady. Ready indicates that reader card polling has been terminated. Not ready indicates that the reader is still polling.
|
|
800
|
+
"""
|
|
801
|
+
self._throw_if_disposed()
|
|
802
|
+
state_raw = c_uint8(0)
|
|
803
|
+
status_raw = c_uint8(0)
|
|
804
|
+
result = RikResult()
|
|
805
|
+
self._native_lib._dll.RikReader_GetTransparentModeStatus(
|
|
806
|
+
byref(result), self._handle.value, byref(state_raw), byref(status_raw)
|
|
807
|
+
)
|
|
808
|
+
ReaderException.raise_if_error(result)
|
|
809
|
+
return TransparentModeState(state_raw.value), TransparentModeStatus(status_raw.value)
|
|
810
|
+
|
|
811
|
+
class ReaderDiscovery:
|
|
812
|
+
"""
|
|
813
|
+
A helper class for discovering connected rfIDEAS readers.
|
|
814
|
+
"""
|
|
815
|
+
|
|
816
|
+
@staticmethod
|
|
817
|
+
def discover_usb_readers() -> list:
|
|
818
|
+
"""
|
|
819
|
+
Enumerates the available rfIDEAS USB readers.
|
|
820
|
+
|
|
821
|
+
Returns:
|
|
822
|
+
List: ReaderDefinition objects describing each connected USB reader.
|
|
823
|
+
|
|
824
|
+
Raises:
|
|
825
|
+
ReaderException: If device enumeration fails.
|
|
826
|
+
"""
|
|
827
|
+
|
|
828
|
+
# Get the native library instance to access the DLL
|
|
829
|
+
native_lib = _NativeLibrary()
|
|
830
|
+
|
|
831
|
+
# First call: get the count of readers
|
|
832
|
+
result = RikResult()
|
|
833
|
+
reader_count = ctypes.c_size_t(0)
|
|
834
|
+
native_lib._dll.Rik_DiscoverUsbReaders(byref(result), None, byref(reader_count))
|
|
835
|
+
ReaderException.raise_if_error(result)
|
|
836
|
+
|
|
837
|
+
# If no readers found, return empty list
|
|
838
|
+
if reader_count.value == 0:
|
|
839
|
+
return []
|
|
840
|
+
|
|
841
|
+
# Second call: get the actual reader information
|
|
842
|
+
readers_array = (ReaderDefinition * reader_count.value)()
|
|
843
|
+
result = RikResult()
|
|
844
|
+
native_lib._dll.Rik_DiscoverUsbReaders(byref(result), readers_array, byref(reader_count))
|
|
845
|
+
ReaderException.raise_if_error(result)
|
|
846
|
+
|
|
847
|
+
# Convert to list of ReaderDefinition objects
|
|
848
|
+
return list(readers_array[:reader_count.value])
|
|
849
|
+
|
|
850
|
+
# Export the main classes
|
|
851
|
+
__all__ = ['AbstractReader', 'Reader', 'ReaderDiscovery', 'ReaderHandle', 'CredentialCallback']
|
|
852
|
+
|