brp-lib 4.0.2__tar.gz → 4.2.0__tar.gz
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.
- {brp_lib-4.0.2 → brp_lib-4.2.0}/PKG-INFO +1 -1
- {brp_lib-4.0.2 → brp_lib-4.2.0}/pyproject.toml +1 -1
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib/__init__.py +9 -1
- brp_lib-4.2.0/src/brp_lib/brp_lib.win32.dll +0 -0
- brp_lib-4.2.0/src/brp_lib/brp_lib.win64.dll +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib/dll_wrapper.py +84 -30
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib/err.py +13 -3
- brp_lib-4.2.0/src/brp_lib/protocols.py +1012 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib.egg-info/PKG-INFO +1 -1
- brp_lib-4.0.2/src/brp_lib/brp_lib.win32.dll +0 -0
- brp_lib-4.0.2/src/brp_lib/brp_lib.win64.dll +0 -0
- brp_lib-4.0.2/src/brp_lib/protocols.py +0 -356
- {brp_lib-4.0.2 → brp_lib-4.2.0}/setup.cfg +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib/py.typed +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib.egg-info/SOURCES.txt +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib.egg-info/dependency_links.txt +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib.egg-info/requires.txt +0 -0
- {brp_lib-4.0.2 → brp_lib-4.2.0}/src/brp_lib.egg-info/top_level.txt +0 -0
|
@@ -3,16 +3,24 @@ import importlib.resources
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Optional, Union
|
|
5
5
|
|
|
6
|
-
from .protocols import
|
|
6
|
+
from .protocols import (
|
|
7
|
+
BrpProtocol, BrpStack, CryptoProtocol, CustomProtocol, IoProtocol, Layer,
|
|
8
|
+
RS232, SecureChannel, UsbHid,
|
|
9
|
+
)
|
|
7
10
|
from .dll_wrapper import c_brp_lib
|
|
8
11
|
from . import err, protocols
|
|
9
12
|
|
|
10
13
|
__all__ = [
|
|
11
14
|
"c_brp_lib",
|
|
15
|
+
"BrpProtocol",
|
|
16
|
+
"IoProtocol",
|
|
17
|
+
"CryptoProtocol",
|
|
12
18
|
"BrpStack",
|
|
13
19
|
"UsbHid",
|
|
14
20
|
"RS232",
|
|
15
21
|
"SecureChannel",
|
|
22
|
+
"CustomProtocol",
|
|
23
|
+
"Layer",
|
|
16
24
|
"protocols",
|
|
17
25
|
"get_brp_lib_path",
|
|
18
26
|
"set_brp_lib_path",
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import ctypes
|
|
2
2
|
import typing
|
|
3
3
|
import functools
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
4
6
|
from contextlib import suppress
|
|
5
7
|
from pathlib import Path
|
|
6
8
|
from typing import Any, Protocol, TypeVar, Callable, Optional
|
|
@@ -105,6 +107,23 @@ class CBrpLibFunction(Protocol[P, R]):
|
|
|
105
107
|
...
|
|
106
108
|
|
|
107
109
|
|
|
110
|
+
def _decode_path(raw: bytes) -> str:
|
|
111
|
+
# the DLL builds paths via ANSI Win32 APIs, so they arrive in the current
|
|
112
|
+
# ANSI code page ("mbcs"), not UTF-8; strict on purpose: never fabricate a
|
|
113
|
+
# wrong path - callers degrade to None instead
|
|
114
|
+
if sys.platform == "win32":
|
|
115
|
+
return raw.decode("mbcs")
|
|
116
|
+
return os.fsdecode(raw)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _encode_path(path: str) -> bytes:
|
|
120
|
+
# strict: a path the ANSI code page cannot represent must fail at set time
|
|
121
|
+
# instead of being silently rewritten by Windows' best-fit mapping
|
|
122
|
+
if sys.platform == "win32":
|
|
123
|
+
return path.encode("mbcs")
|
|
124
|
+
return os.fsencode(path)
|
|
125
|
+
|
|
126
|
+
|
|
108
127
|
CharP = Annotated[ctypes.Array[ctypes.c_char], ctypes.c_char_p]
|
|
109
128
|
CharPP = Annotated[Any, ctypes.POINTER(ctypes.c_char_p)]
|
|
110
129
|
CInt = Annotated[int, ctypes.c_int]
|
|
@@ -125,6 +144,7 @@ CMempool = Annotated[Any, mempool]
|
|
|
125
144
|
CIoiter = Annotated[Any, ioiter]
|
|
126
145
|
CIoiterP = Annotated[Any, ioiter_p]
|
|
127
146
|
CUShort = Annotated[int, ctypes.c_ushort]
|
|
147
|
+
CPath = Annotated[Optional[str], ctypes.c_char_p, (_decode_path, _encode_path)]
|
|
128
148
|
|
|
129
149
|
ErrorCode = Annotated[None, errcode]
|
|
130
150
|
|
|
@@ -140,48 +160,81 @@ def _to_ctype(t: Any) -> Any:
|
|
|
140
160
|
return t
|
|
141
161
|
|
|
142
162
|
|
|
143
|
-
def
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
def _get_codec(t: Any) -> Any:
|
|
164
|
+
# optional third Annotated arg: a (decode, encode) pair converting this type
|
|
165
|
+
# at the C boundary (decode: C result -> python, encode: python arg -> C)
|
|
166
|
+
args = typing.get_args(t)
|
|
167
|
+
return args[2] if len(args) > 2 else None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _with_codecs(
|
|
171
|
+
fn: Callable[..., Any], argtypes: Any, restype: Any
|
|
172
|
+
) -> Callable[..., Any]:
|
|
173
|
+
arg_codecs = [_get_codec(t) for t in argtypes]
|
|
174
|
+
result_codec = _get_codec(restype)
|
|
175
|
+
if not any(arg_codecs) and result_codec is None:
|
|
176
|
+
return fn
|
|
177
|
+
|
|
178
|
+
@functools.wraps(fn)
|
|
179
|
+
def wrapper(*args: Any) -> Any:
|
|
180
|
+
converted = [
|
|
181
|
+
codec[1](arg) if codec is not None and arg is not None else arg
|
|
182
|
+
for codec, arg in zip(arg_codecs, args)
|
|
183
|
+
]
|
|
184
|
+
result = fn(*converted)
|
|
185
|
+
if result_codec is not None and result is not None:
|
|
186
|
+
return result_codec[0](result)
|
|
187
|
+
return result
|
|
188
|
+
|
|
189
|
+
return wrapper
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _get_log_link(lib: "CBrpLib", prot: Any) -> Optional[str]:
|
|
193
|
+
log_path = lib.brp_get_log_path(prot, None)
|
|
194
|
+
if not log_path:
|
|
146
195
|
return None
|
|
147
196
|
|
|
148
|
-
path = Path(
|
|
197
|
+
path = Path(log_path)
|
|
149
198
|
if not path.exists():
|
|
150
199
|
return None
|
|
151
200
|
url = f"{path.as_uri()}"
|
|
152
201
|
|
|
153
202
|
anchor_ptr = ctypes.c_char_p()
|
|
154
|
-
|
|
203
|
+
lib.brp_get_current_log_anchor(prot, ctypes.byref(anchor_ptr), None)
|
|
155
204
|
if anchor_ptr.value:
|
|
156
205
|
return f"{url}{anchor_ptr.value.decode('utf-8')}"
|
|
157
206
|
return url
|
|
158
207
|
|
|
159
208
|
|
|
160
|
-
def with_error_handling(fn: Callable[P, int]) -> Callable[P, None]:
|
|
209
|
+
def with_error_handling(lib: "CBrpLib", fn: Callable[P, int]) -> Callable[P, None]:
|
|
210
|
+
"""Map nonzero errcodes to BrpError, attaching the log link looked up via
|
|
211
|
+
``lib`` — the instance the wrapped function belongs to, not the global."""
|
|
161
212
|
@functools.wraps(fn)
|
|
162
213
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> None:
|
|
163
214
|
result = fn(*args, **kwargs)
|
|
164
215
|
if result:
|
|
165
216
|
log_url = None
|
|
166
|
-
with suppress():
|
|
217
|
+
with suppress(Exception):
|
|
167
218
|
if len(args) > 0 and isinstance(args[0], protocol):
|
|
168
|
-
log_url = _get_log_link(args[0])
|
|
219
|
+
log_url = _get_log_link(lib, args[0])
|
|
169
220
|
raise BrpError.from_error_code(result, log_url=log_url)
|
|
170
221
|
|
|
171
222
|
return wrapper
|
|
172
223
|
|
|
173
224
|
|
|
174
|
-
def _not_implemented(name: str, version: str, *args: object, **kwargs: object) -> Never:
|
|
175
|
-
raise NotImplementedError(f"{name} is not implemented in brp_lib {version}")
|
|
176
|
-
|
|
177
|
-
|
|
178
225
|
class CBrpLib:
|
|
179
226
|
brp_get_version: CBrpLibFunction[[], CharP]
|
|
180
227
|
brp_create: CBrpLibFunction[[], CProtocol]
|
|
228
|
+
brp_create_custom: CBrpLibFunction[[CInt], CProtocol]
|
|
181
229
|
brp_destroy: CBrpLibFunction[[CProtocol], ErrorCode]
|
|
230
|
+
brp_protocol_free: CBrpLibFunction[[CProtocol], None]
|
|
182
231
|
brp_set_io: CBrpLibFunction[[CProtocol, CProtocol], ErrorCode]
|
|
232
|
+
brp_set_layer: CBrpLibFunction[[CProtocol, CInt, CProtocol], ErrorCode]
|
|
233
|
+
brp_get_layer: CBrpLibFunction[[CProtocol, CInt], CProtocol]
|
|
234
|
+
brp_detach_layer: CBrpLibFunction[[CProtocol, CInt], CProtocol]
|
|
183
235
|
brp_open: CBrpLibFunction[[CProtocol], ErrorCode]
|
|
184
236
|
brp_close: CBrpLibFunction[[CProtocol], ErrorCode]
|
|
237
|
+
brp_flush: CBrpLibFunction[[CProtocol], ErrorCode]
|
|
185
238
|
brp_suppress_monitoring: CBrpLibFunction[[CProtocol], ErrorCode]
|
|
186
239
|
brp_get_io_id: CBrpLibFunction[[CProtocol, CharPP, CFrame], ErrorCode]
|
|
187
240
|
brp_get_friendly_name: CBrpLibFunction[[CProtocol, CharPP], ErrorCode]
|
|
@@ -209,9 +262,9 @@ class CBrpLib:
|
|
|
209
262
|
brp_frame_read_eof: CBrpLibFunction[[CFrameReader], CBool]
|
|
210
263
|
brp_annotation_start: CBrpLibFunction[[CProtocol], None]
|
|
211
264
|
brp_annotation_end: CBrpLibFunction[[CProtocol, CBool, CharP], None]
|
|
212
|
-
brp_set_log_path: CBrpLibFunction[[CProtocol,
|
|
265
|
+
brp_set_log_path: CBrpLibFunction[[CProtocol, CPath], ErrorCode]
|
|
213
266
|
brp_get_current_log_anchor: CBrpLibFunction[[CProtocol, CharPP, CMempool], ErrorCode]
|
|
214
|
-
brp_get_log_path: CBrpLibFunction[[CProtocol, CMempool],
|
|
267
|
+
brp_get_log_path: CBrpLibFunction[[CProtocol, CMempool], CPath]
|
|
215
268
|
|
|
216
269
|
def __init__(self) -> None:
|
|
217
270
|
self.__dll_path: Optional[Path] = None
|
|
@@ -222,28 +275,29 @@ class CBrpLib:
|
|
|
222
275
|
|
|
223
276
|
@dll_path.setter
|
|
224
277
|
def dll_path(self, dll_path: Path) -> None:
|
|
225
|
-
|
|
226
|
-
dll = ctypes.CDLL(str(
|
|
278
|
+
abs_path = dll_path.absolute()
|
|
279
|
+
dll = ctypes.CDLL(str(abs_path))
|
|
280
|
+
if getattr(dll, "brp_get_version", None) is None:
|
|
281
|
+
raise ValueError(
|
|
282
|
+
f"{abs_path} is not a brp_lib library (does not export brp_get_version)"
|
|
283
|
+
)
|
|
284
|
+
self.__dll_path = abs_path
|
|
227
285
|
|
|
228
286
|
for name, annotation in type(self).__annotations__.items():
|
|
229
287
|
if typing.get_origin(annotation) == CBrpLibFunction:
|
|
230
288
|
argtypes, restype = typing.get_args(annotation)
|
|
231
|
-
fn = getattr(dll, name,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if name != "brp_get_version"
|
|
238
|
-
else "<unknown>"
|
|
239
|
-
)
|
|
240
|
-
else:
|
|
241
|
-
fn.restype = _to_ctype(restype)
|
|
242
|
-
fn.argtypes = tuple(map(_to_ctype, argtypes))
|
|
243
|
-
if restype == ErrorCode:
|
|
244
|
-
fn = with_error_handling(fn)
|
|
289
|
+
fn: Any = getattr(dll, name, functools.partial(self._raise_not_implemented, name))
|
|
290
|
+
fn.restype = _to_ctype(restype)
|
|
291
|
+
fn.argtypes = tuple(map(_to_ctype, argtypes))
|
|
292
|
+
fn = _with_codecs(fn, argtypes, restype)
|
|
293
|
+
if restype == ErrorCode:
|
|
294
|
+
fn = with_error_handling(self, fn)
|
|
245
295
|
setattr(self, name, fn)
|
|
246
296
|
|
|
297
|
+
def _raise_not_implemented(self, name: str, *args: object, **kwargs: object) -> Never:
|
|
298
|
+
version = bytes(self.brp_get_version()).decode("ascii")
|
|
299
|
+
raise NotImplementedError(f"{name} is not implemented in brp_lib {version}")
|
|
300
|
+
|
|
247
301
|
def __getattr__(self, item: str) -> Any:
|
|
248
302
|
if item in type(self).__annotations__:
|
|
249
303
|
raise RuntimeError("Please initialize the brp_lib path calling `brp_lib.set_brp_lib_path('.../libbrp_lib.so')`.")
|
|
@@ -3,6 +3,7 @@ from typing import Dict, Type, Optional
|
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
5
|
"BrpError",
|
|
6
|
+
"UnknownError",
|
|
6
7
|
"DeviceError",
|
|
7
8
|
"CommunicationError",
|
|
8
9
|
"CommUnsupported",
|
|
@@ -63,8 +64,10 @@ class BrpError(Exception, metaclass=abc.ABCMeta):
|
|
|
63
64
|
|
|
64
65
|
@classmethod
|
|
65
66
|
def from_error_code(cls, ec: int, *, log_url: Optional[str] = None) -> "BrpError":
|
|
66
|
-
error_class
|
|
67
|
-
|
|
67
|
+
error_class = cls.ErrorCodeMap.get(ec)
|
|
68
|
+
if error_class is not None:
|
|
69
|
+
return error_class(log_url=log_url)
|
|
70
|
+
return UnknownError(ec, log_url=log_url)
|
|
68
71
|
|
|
69
72
|
def __init__(self, message: str = "", *, log_url: Optional[str] = None) -> None:
|
|
70
73
|
self.log_url = log_url
|
|
@@ -75,7 +78,7 @@ class BrpError(Exception, metaclass=abc.ABCMeta):
|
|
|
75
78
|
map(str,
|
|
76
79
|
filter(
|
|
77
80
|
lambda i: i is not None, [
|
|
78
|
-
f"0x{self.ErrorCode:08X} {super()
|
|
81
|
+
f"0x{self.ErrorCode:08X} {super().__str__()}\n",
|
|
79
82
|
f"DESC: {self.__doc__.strip() if self.__doc__ else None}",
|
|
80
83
|
f"DOCS: {self.URL}" if self.URL else None,
|
|
81
84
|
f"LOGS: {self.log_url}" if self.log_url else None,
|
|
@@ -85,6 +88,13 @@ class BrpError(Exception, metaclass=abc.ABCMeta):
|
|
|
85
88
|
)
|
|
86
89
|
|
|
87
90
|
|
|
91
|
+
class UnknownError(BrpError):
|
|
92
|
+
"""An error with an error code not known to the SDK."""
|
|
93
|
+
def __init__(self, error_code: int, *, log_url: Optional[str] = None) -> None:
|
|
94
|
+
self.ErrorCode = error_code
|
|
95
|
+
super().__init__(log_url=log_url)
|
|
96
|
+
|
|
97
|
+
|
|
88
98
|
class CommunicationError(BrpError, metaclass=abc.ABCMeta):
|
|
89
99
|
"""Any kind of device <-> host communication problem"""
|
|
90
100
|
|