objutils 0.7.0__tar.gz → 0.7.2__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.
- {objutils-0.7.0 → objutils-0.7.2}/PKG-INFO +2 -1
- {objutils-0.7.0 → objutils-0.7.2}/objutils/__init__.py +1 -1
- {objutils-0.7.0 → objutils-0.7.2}/objutils/section.py +70 -44
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_section.py +136 -0
- objutils-0.7.2/objutils/utils/arduino.py +51 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/version.py +1 -1
- {objutils-0.7.0 → objutils-0.7.2}/pyproject.toml +4 -2
- {objutils-0.7.0 → objutils-0.7.2}/LICENSE +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/build_ext.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/docs/README.rst +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/.coveragerc +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/ash.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/binfile.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/checksums.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/cosmac.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/constants.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/encoding.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/lineprog.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/sm.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/arm/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/arm/attributes.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/defs.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/model.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/emon52.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/etek.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/exceptions.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/ctre.hpp +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/difflib.h +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/exceptions.cpp +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/exceptions.hpp +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/wrapper.cpp +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/fpc.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/hexdump.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/hexfile.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/ieee695.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/ihex.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/image.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/logger.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/mostec.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/pickleif.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/rca.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/readers.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/registry.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_arm_attrs.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_extract.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_info.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_syms.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_hex_info.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/shf.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/sig.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/srec.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tek.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_arm_attributes.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_ash.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_checksums.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_cygpath.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_diff_bin.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_emon52.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_fpc.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_hexdump.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_hexfile.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_ihex.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_image.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_mostec.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_readers.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_registry.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_repr.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_shf.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_srec.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_tek.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_titext.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/titxt.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/utils/__init__.py +0 -0
- {objutils-0.7.0 → objutils-0.7.2}/objutils/utils/diff.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: objutils
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Objectfile library for Python
|
|
5
5
|
License: GPLv2
|
|
6
6
|
Keywords: hex files,intel hex,s19,srec,srecords,object files,map files,embedded,microcontroller,ECU,shf,rfc4194
|
|
@@ -26,6 +26,7 @@ Requires-Dist: darglint (>=1.8.1,<2.0.0)
|
|
|
26
26
|
Requires-Dist: flake8 (>=7.0.0,<8.0.0)
|
|
27
27
|
Requires-Dist: isort (>=5.13.2,<6.0.0)
|
|
28
28
|
Requires-Dist: mako (>=1.3.3,<2.0.0)
|
|
29
|
+
Requires-Dist: numpy (<=2.2.5)
|
|
29
30
|
Requires-Dist: prettier (>=0.0.7,<0.0.8)
|
|
30
31
|
Requires-Dist: rich (>=13.8.1,<14.0.0)
|
|
31
32
|
Requires-Dist: sqlalchemy (>=2.0.29,<3.0.0)
|
|
@@ -35,11 +35,14 @@ from array import array
|
|
|
35
35
|
from collections import namedtuple
|
|
36
36
|
from copy import copy
|
|
37
37
|
from dataclasses import dataclass, field
|
|
38
|
-
from
|
|
38
|
+
from functools import reduce
|
|
39
|
+
from operator import attrgetter, mul
|
|
39
40
|
from typing import Any, List, Union
|
|
40
41
|
|
|
42
|
+
import numpy as np
|
|
43
|
+
|
|
41
44
|
import objutils.hexdump as hexdump
|
|
42
|
-
from objutils.exceptions import
|
|
45
|
+
from objutils.exceptions import InvalidAddressError
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
try:
|
|
@@ -176,6 +179,43 @@ def _data_converter(data: Union[str, bytearray, array, Any]) -> bytearray:
|
|
|
176
179
|
return data
|
|
177
180
|
|
|
178
181
|
|
|
182
|
+
def fortran_array_from_buffer(arr: bytearray, shape: tuple, dtype: str) -> np.ndarray:
|
|
183
|
+
if len(shape) <= 2:
|
|
184
|
+
return np.frombuffer(arr, dtype=dtype).reshape(shape[::-1]).T
|
|
185
|
+
# shape = list(reversed(shape))
|
|
186
|
+
lhs = shape[:-2]
|
|
187
|
+
num_slices = reduce(mul, lhs, 1)
|
|
188
|
+
rhs = shape[-2:]
|
|
189
|
+
slice_len = reduce(mul, rhs, 1)
|
|
190
|
+
buf = arr.copy()
|
|
191
|
+
offset = 0
|
|
192
|
+
for idx in range(num_slices):
|
|
193
|
+
ddx = buf[offset : offset + slice_len]
|
|
194
|
+
res = np.frombuffer(ddx, dtype=dtype).reshape(*reversed(rhs)).T
|
|
195
|
+
buf[offset : offset + slice_len] = res.tobytes()
|
|
196
|
+
offset += slice_len
|
|
197
|
+
return np.frombuffer(buf, dtype=dtype).reshape(shape)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def fortran_array_to_buffer(array: np.ndarray) -> bytearray:
|
|
201
|
+
shape = array.shape
|
|
202
|
+
if array.ndim <= 2:
|
|
203
|
+
return array.tobytes("F")
|
|
204
|
+
else:
|
|
205
|
+
lhs = shape[:-2]
|
|
206
|
+
num_slices = reduce(mul, lhs, 1)
|
|
207
|
+
rhs = shape[-2:]
|
|
208
|
+
slice_len = reduce(mul, rhs, 1)
|
|
209
|
+
rs_arr = array.reshape(num_slices, *rhs)
|
|
210
|
+
offset = 0
|
|
211
|
+
result = bytearray(array.nbytes)
|
|
212
|
+
for idx in range(num_slices):
|
|
213
|
+
slice = rs_arr[idx]
|
|
214
|
+
result[offset : offset + slice_len] = slice.T.tobytes()
|
|
215
|
+
offset += slice_len
|
|
216
|
+
return result
|
|
217
|
+
|
|
218
|
+
|
|
179
219
|
@dataclass(repr=False, order=True)
|
|
180
220
|
class Section:
|
|
181
221
|
"""Manage sections.
|
|
@@ -206,7 +246,7 @@ class Section:
|
|
|
206
246
|
def tolist(self) -> List[int]:
|
|
207
247
|
return array("B", self.data).tolist()
|
|
208
248
|
|
|
209
|
-
def _verify_dtype(self, dtype):
|
|
249
|
+
def _verify_dtype(self, dtype: str) -> str:
|
|
210
250
|
""" """
|
|
211
251
|
dtype = dtype.lower().strip()
|
|
212
252
|
if dtype == "byte":
|
|
@@ -219,7 +259,7 @@ class Section:
|
|
|
219
259
|
raise TypeError(f"Invalid datatype {dtype!r}")
|
|
220
260
|
return dtype.split("_")
|
|
221
261
|
|
|
222
|
-
def _getformat(self, dtype, length=1):
|
|
262
|
+
def _getformat(self, dtype: str, length: int = 1) -> str:
|
|
223
263
|
""" """
|
|
224
264
|
fmt, bo = self._verify_dtype(dtype)
|
|
225
265
|
|
|
@@ -228,7 +268,7 @@ class Section:
|
|
|
228
268
|
else:
|
|
229
269
|
return f"{BYTEORDER.get(bo)}{FORMATS.get(fmt)}"
|
|
230
270
|
|
|
231
|
-
def read(self, addr, length, **kws):
|
|
271
|
+
def read(self, addr: int, length: int, **kws) -> bytes:
|
|
232
272
|
"""
|
|
233
273
|
Parameters
|
|
234
274
|
----------
|
|
@@ -244,7 +284,7 @@ class Section:
|
|
|
244
284
|
data = self.data[offset : offset + length]
|
|
245
285
|
return data
|
|
246
286
|
|
|
247
|
-
def write(self, addr, data, **kws):
|
|
287
|
+
def write(self, addr: int, data: bytes, **kws) -> None:
|
|
248
288
|
"""
|
|
249
289
|
Parameters
|
|
250
290
|
----------
|
|
@@ -262,7 +302,7 @@ class Section:
|
|
|
262
302
|
raise InvalidAddressError(f"write(0x{addr:08x}) access out of bounds.")
|
|
263
303
|
self.data[offset : offset + length] = data
|
|
264
304
|
|
|
265
|
-
def read_numeric(self, addr, dtype, **kws):
|
|
305
|
+
def read_numeric(self, addr: int, dtype: str, **kws) -> Union[int, float]:
|
|
266
306
|
offset = addr - self.start_address
|
|
267
307
|
if offset < 0:
|
|
268
308
|
raise InvalidAddressError(f"read_numeric(0x{addr:08x}) access out of bounds.")
|
|
@@ -276,7 +316,7 @@ class Section:
|
|
|
276
316
|
data = self.apply_bitmask(data, dtype, bit_mask)
|
|
277
317
|
return struct.unpack(fmt, data)[0]
|
|
278
318
|
|
|
279
|
-
def apply_bitmask(self, data, dtype, bit_mask):
|
|
319
|
+
def apply_bitmask(self, data: bytes, dtype: str, bit_mask: int) -> bytes:
|
|
280
320
|
""" """
|
|
281
321
|
dtype, byteorder = dtype.lower().strip().split("_")
|
|
282
322
|
byteorder = "little" if byteorder == "le" else "big"
|
|
@@ -286,7 +326,7 @@ class Section:
|
|
|
286
326
|
tmp &= bit_mask
|
|
287
327
|
return tmp.to_bytes(data_size, byteorder, signed=False)
|
|
288
328
|
|
|
289
|
-
def write_numeric(self, addr, value, dtype, **kws):
|
|
329
|
+
def write_numeric(self, addr: int, value: Union[int, float], dtype: str, **kws) -> None:
|
|
290
330
|
offset = addr - self.start_address
|
|
291
331
|
if offset < 0:
|
|
292
332
|
raise InvalidAddressError(f"write_numeric(0x{addr:08x}) access out of bounds.")
|
|
@@ -299,7 +339,7 @@ class Section:
|
|
|
299
339
|
|
|
300
340
|
self.data[offset : offset + data_size] = struct.pack(fmt, value)
|
|
301
341
|
|
|
302
|
-
def read_numeric_array(self, addr, length, dtype, **kws):
|
|
342
|
+
def read_numeric_array(self, addr: int, length: int, dtype: str, **kws) -> Union[List[int], List[float]]:
|
|
303
343
|
offset = addr - self.start_address
|
|
304
344
|
if offset < 0:
|
|
305
345
|
raise InvalidAddressError(f"read_numeric_array(0x{addr:08x}) access out of bounds.")
|
|
@@ -310,7 +350,7 @@ class Section:
|
|
|
310
350
|
data = self.data[offset : offset + data_size]
|
|
311
351
|
return struct.unpack(fmt, data)
|
|
312
352
|
|
|
313
|
-
def write_numeric_array(self, addr, data, dtype, **kws):
|
|
353
|
+
def write_numeric_array(self, addr: int, data: Union[List[int], List[float]], dtype: str, **kws) -> None:
|
|
314
354
|
if not hasattr(data, "__iter__"):
|
|
315
355
|
raise TypeError("data must be iterable")
|
|
316
356
|
length = len(data)
|
|
@@ -323,7 +363,7 @@ class Section:
|
|
|
323
363
|
raise InvalidAddressError(f"write_numeric_array(0x{addr:08x}) access out of bounds.")
|
|
324
364
|
self.data[offset : offset + data_size] = struct.pack(fmt, *data)
|
|
325
365
|
|
|
326
|
-
def read_string(self, addr, encoding="latin1", length
|
|
366
|
+
def read_string(self, addr: int, encoding: str = "latin1", length: int = -1, **kws) -> str:
|
|
327
367
|
offset = addr - self.start_address
|
|
328
368
|
if offset < 0:
|
|
329
369
|
raise InvalidAddressError(f"read_string(0x{addr:08x}) access out of bounds.")
|
|
@@ -335,19 +375,15 @@ class Section:
|
|
|
335
375
|
raise TypeError("Unterminated String!!!") # TODO: Testcase.
|
|
336
376
|
return self.data[offset : offset + pos].decode(encoding=encoding)
|
|
337
377
|
|
|
338
|
-
def write_string(self, addr, value, encoding="latin1", **kws):
|
|
378
|
+
def write_string(self, addr: int, value: str, encoding: str = "latin1", **kws):
|
|
339
379
|
offset = addr - self.start_address
|
|
340
380
|
if offset < 0:
|
|
341
381
|
raise InvalidAddressError(f"write_string(0x{addr:08x}) access out of bounds.")
|
|
342
382
|
self.data[offset : offset + len(value)] = bytes(value, encoding=encoding)
|
|
343
383
|
self.data[offset + len(value)] = 0
|
|
344
384
|
|
|
345
|
-
def write_ndarray(self, addr, array, order=None, **kws):
|
|
385
|
+
def write_ndarray(self, addr: int, array: np.ndarray, order: str = None, **kws) -> None:
|
|
346
386
|
""" """
|
|
347
|
-
try:
|
|
348
|
-
import numpy as np
|
|
349
|
-
except ImportError as e:
|
|
350
|
-
raise FeatureNotAvailableError("write_ndarray() requires Numpy.") from e
|
|
351
387
|
offset = addr - self.start_address
|
|
352
388
|
if offset < 0:
|
|
353
389
|
raise InvalidAddressError(f"write_ndarray(0x{addr:08x}) access out of bounds.")
|
|
@@ -356,36 +392,26 @@ class Section:
|
|
|
356
392
|
data_size = array.nbytes
|
|
357
393
|
if offset + data_size > self.length:
|
|
358
394
|
raise InvalidAddressError(f"write_ndarray(0x{addr:08x}) access out of bounds.")
|
|
359
|
-
|
|
395
|
+
if order is not None and order == "F":
|
|
396
|
+
self.data[offset : offset + data_size] = fortran_array_to_buffer(array=array)
|
|
397
|
+
else:
|
|
398
|
+
self.data[offset : offset + data_size] = array.tobytes()
|
|
360
399
|
|
|
361
|
-
def read_ndarray(self, addr, length, dtype, shape=None, order=None, **kws):
|
|
400
|
+
def read_ndarray(self, addr: int, length: int, dtype: str, shape: tuple = None, order: str = None, **kws) -> np.ndarray:
|
|
362
401
|
""" """
|
|
363
|
-
try:
|
|
364
|
-
import numpy as np
|
|
365
|
-
except ImportError as e:
|
|
366
|
-
raise FeatureNotAvailableError("read_ndarray() requires Numpy.") from e
|
|
367
402
|
offset = addr - self.start_address
|
|
368
403
|
if offset < 0:
|
|
369
404
|
raise InvalidAddressError(f"read_ndarray(0x{addr:08x}) access out of bounds.")
|
|
370
405
|
if offset + length > self.length:
|
|
371
406
|
raise InvalidAddressError(f"read_ndarray(0x{addr:08x}) access out of bounds.")
|
|
372
|
-
|
|
373
|
-
"""
|
|
374
|
-
If the buffer has data that is not in machine byte-order, this should
|
|
375
|
-
be specified as part of the data-type, e.g.::
|
|
376
|
-
|
|
377
|
-
>>> dt = np.dtype(int)
|
|
378
|
-
>>> dt = dt.newbyteorder('>')
|
|
379
|
-
>>> np.frombuffer(buf, dtype=dt)
|
|
380
|
-
"""
|
|
381
407
|
type_, byte_order = self._verify_dtype(dtype)
|
|
382
408
|
dt = np.dtype(type_)
|
|
383
409
|
dt = dt.newbyteorder(BYTEORDER.get(byte_order))
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return arr.T # Fortran deposit, i.e. col-maj means transposition.
|
|
410
|
+
if order is not None and order == "F":
|
|
411
|
+
arr = fortran_array_from_buffer(arr=self.data[offset : offset + length], shape=shape, dtype=dt)
|
|
387
412
|
else:
|
|
388
|
-
|
|
413
|
+
arr = np.frombuffer(self.data[offset : offset + length], dtype=dt).reshape(shape)
|
|
414
|
+
return arr
|
|
389
415
|
|
|
390
416
|
"""
|
|
391
417
|
def write_timestamp():
|
|
@@ -395,33 +421,33 @@ class Section:
|
|
|
395
421
|
pass
|
|
396
422
|
"""
|
|
397
423
|
|
|
398
|
-
def find(self, expr, addr
|
|
424
|
+
def find(self, expr: str, addr: int = -1) -> int:
|
|
399
425
|
for item in re.finditer(bytes(expr), self.data):
|
|
400
426
|
yield (self.start_address + item.start(), item.end() - item.start())
|
|
401
427
|
|
|
402
|
-
def __repr__(self):
|
|
428
|
+
def __repr__(self) -> str:
|
|
403
429
|
return "Section(address = 0X{:08X}, length = {:d}, data = {})".format(
|
|
404
430
|
self.start_address,
|
|
405
431
|
self.length,
|
|
406
432
|
self.repr.repr(memoryview(self.data).tobytes()),
|
|
407
433
|
)
|
|
408
434
|
|
|
409
|
-
def __len__(self):
|
|
435
|
+
def __len__(self) -> int:
|
|
410
436
|
return len(self.data)
|
|
411
437
|
|
|
412
438
|
@property
|
|
413
|
-
def length(self):
|
|
439
|
+
def length(self) -> int:
|
|
414
440
|
return len(self)
|
|
415
441
|
|
|
416
|
-
def __contains__(self, addr):
|
|
442
|
+
def __contains__(self, addr) -> bool:
|
|
417
443
|
return self.start_address <= addr < (self.start_address + self.length)
|
|
418
444
|
|
|
419
445
|
@property
|
|
420
|
-
def address(self): # Alias
|
|
446
|
+
def address(self) -> int: # Alias
|
|
421
447
|
return self.start_address
|
|
422
448
|
|
|
423
449
|
|
|
424
|
-
def join_sections(sections):
|
|
450
|
+
def join_sections(sections: List[Section]) -> List[Section]:
|
|
425
451
|
result_sections = []
|
|
426
452
|
sections.sort(key=attrgetter("start_address"))
|
|
427
453
|
prev_section = Section()
|
|
@@ -631,3 +631,139 @@ def test_read_ndarray_flat():
|
|
|
631
631
|
|
|
632
632
|
result = sec.read_ndarray(0x1000, 24, "int32_le")
|
|
633
633
|
assert np.array_equal(result, np.array([11, 22, 33, 44, 55, 66]))
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
@pytest.mark.skipif("NUMPY_SUPPORT == False")
|
|
637
|
+
def test_read_ndarray_fortan_01():
|
|
638
|
+
sec = Section(
|
|
639
|
+
start_address=0x1000,
|
|
640
|
+
data=bytearray(b"\x01\x00\x04\x00\x07\x00\n\x00\x02\x00\x05\x00\x08\x00\x0b\x00\x03\x00\x06\x00\t\x00\x0c\x00"),
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
result = sec.read_ndarray(0x1000, 24, shape=(3, 4), order="F", dtype="int16_le")
|
|
644
|
+
assert np.array_equal(
|
|
645
|
+
result,
|
|
646
|
+
np.array(
|
|
647
|
+
[
|
|
648
|
+
[1, 2, 3],
|
|
649
|
+
[
|
|
650
|
+
4,
|
|
651
|
+
5,
|
|
652
|
+
6,
|
|
653
|
+
],
|
|
654
|
+
[7, 8, 9],
|
|
655
|
+
[10, 11, 12],
|
|
656
|
+
],
|
|
657
|
+
dtype=np.int16,
|
|
658
|
+
),
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
@pytest.mark.skipif("NUMPY_SUPPORT == False")
|
|
663
|
+
def test_read_ndarray_fortan_02():
|
|
664
|
+
sec = Section(
|
|
665
|
+
start_address=0x1000,
|
|
666
|
+
data=[
|
|
667
|
+
1,
|
|
668
|
+
3,
|
|
669
|
+
5,
|
|
670
|
+
2,
|
|
671
|
+
4,
|
|
672
|
+
6,
|
|
673
|
+
7,
|
|
674
|
+
9,
|
|
675
|
+
11,
|
|
676
|
+
8,
|
|
677
|
+
10,
|
|
678
|
+
12,
|
|
679
|
+
13,
|
|
680
|
+
15,
|
|
681
|
+
17,
|
|
682
|
+
14,
|
|
683
|
+
16,
|
|
684
|
+
18,
|
|
685
|
+
19,
|
|
686
|
+
21,
|
|
687
|
+
23,
|
|
688
|
+
20,
|
|
689
|
+
22,
|
|
690
|
+
24,
|
|
691
|
+
25,
|
|
692
|
+
27,
|
|
693
|
+
29,
|
|
694
|
+
26,
|
|
695
|
+
28,
|
|
696
|
+
30,
|
|
697
|
+
31,
|
|
698
|
+
33,
|
|
699
|
+
35,
|
|
700
|
+
32,
|
|
701
|
+
34,
|
|
702
|
+
36,
|
|
703
|
+
37,
|
|
704
|
+
39,
|
|
705
|
+
41,
|
|
706
|
+
38,
|
|
707
|
+
40,
|
|
708
|
+
42,
|
|
709
|
+
43,
|
|
710
|
+
45,
|
|
711
|
+
47,
|
|
712
|
+
44,
|
|
713
|
+
46,
|
|
714
|
+
48,
|
|
715
|
+
],
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
result = sec.read_ndarray(0x1000, 48, shape=(2, 4, 3, 2), order="F", dtype="int8_le")
|
|
719
|
+
assert np.array_equal(
|
|
720
|
+
result,
|
|
721
|
+
np.array(
|
|
722
|
+
[
|
|
723
|
+
[
|
|
724
|
+
[[1, 2], [3, 4], [5, 6]],
|
|
725
|
+
[[7, 8], [9, 10], [11, 12]],
|
|
726
|
+
[[13, 14], [15, 16], [17, 18]],
|
|
727
|
+
[[19, 20], [21, 22], [23, 24]],
|
|
728
|
+
],
|
|
729
|
+
[
|
|
730
|
+
[[25, 26], [27, 28], [29, 30]],
|
|
731
|
+
[[31, 32], [33, 34], [35, 36]],
|
|
732
|
+
[[37, 38], [39, 40], [41, 42]],
|
|
733
|
+
[[43, 44], [45, 46], [47, 48]],
|
|
734
|
+
],
|
|
735
|
+
],
|
|
736
|
+
dtype=np.int8,
|
|
737
|
+
),
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
@pytest.mark.skipif("NUMPY_SUPPORT == False")
|
|
742
|
+
def test_write_ndarray_fortan_01():
|
|
743
|
+
sec = Section(start_address=0x1000, data=bytearray(128))
|
|
744
|
+
arr = np.array(
|
|
745
|
+
[
|
|
746
|
+
[[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]], [[13, 14], [15, 16], [17, 18]], [[19, 20], [21, 22], [23, 24]]],
|
|
747
|
+
[
|
|
748
|
+
[[25, 26], [27, 28], [29, 30]],
|
|
749
|
+
[[31, 32], [33, 34], [35, 36]],
|
|
750
|
+
[[37, 38], [39, 40], [41, 42]],
|
|
751
|
+
[[43, 44], [45, 46], [47, 48]],
|
|
752
|
+
],
|
|
753
|
+
],
|
|
754
|
+
dtype=np.int8,
|
|
755
|
+
)
|
|
756
|
+
sec.write_ndarray(0x1000, arr, order="F")
|
|
757
|
+
assert sec.read(0x1000, 48) == bytearray(
|
|
758
|
+
b"\x01\x03\x05\x02\x04\x06\x07\t\x0b\x08\n\x0c\r\x0f\x11\x0e\x10\x12\x13\x15\x17\x14\x16\x18\x19\x1b\x1d\x1a\x1c\x1e\x1f!# \"$%')&(*+-/,.0"
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
@pytest.mark.skipif("NUMPY_SUPPORT == False")
|
|
763
|
+
def test_write_ndarray_fortan_02():
|
|
764
|
+
sec = Section(start_address=0x1000, data=bytearray(128))
|
|
765
|
+
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.int16)
|
|
766
|
+
sec.write_ndarray(0x1000, arr, order="F")
|
|
767
|
+
assert sec.read(0x1000, 24) == bytearray(
|
|
768
|
+
b"\x01\x00\x04\x00\x07\x00\n\x00\x02\x00\x05\x00\x08\x00\x0b\x00\x03\x00\x06\x00\t\x00\x0c\x00"
|
|
769
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/python
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ARDUINO_TEMP_BASE_A = Path(tempfile.gettempdir()) / "arduino" / "sketches"
|
|
9
|
+
ARDUINO_TEMP_BASE_B = Path(Path.home()) / "AppData" / "Local" / "arduino" / "sketches"
|
|
10
|
+
|
|
11
|
+
SUFFIXES = [".eep", ".elf", ".hex", ".map"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def build_artifacts(sketch_name: str) -> Path:
|
|
15
|
+
"""Get filenames of Arduino build artifact, e.g. elf-file."""
|
|
16
|
+
result = {}
|
|
17
|
+
path = Path(sketch_name)
|
|
18
|
+
if not path.exists():
|
|
19
|
+
raise ValueError(f"{sketch_name} not found.")
|
|
20
|
+
if path.is_file():
|
|
21
|
+
if path.suffix != ".ino":
|
|
22
|
+
raise ValueError("Expected file-extension '.ino'.")
|
|
23
|
+
path_to_dir = str(path.parent)
|
|
24
|
+
elif path.is_dir():
|
|
25
|
+
path_to_dir = str(path)
|
|
26
|
+
if ARDUINO_TEMP_BASE_A.exists():
|
|
27
|
+
base = ARDUINO_TEMP_BASE_A
|
|
28
|
+
elif ARDUINO_TEMP_BASE_B.exists():
|
|
29
|
+
base = ARDUINO_TEMP_BASE_B
|
|
30
|
+
else:
|
|
31
|
+
raise ValueError("Could not determine Arduino base directory")
|
|
32
|
+
sketch_dir = base / hashlib.md5(path_to_dir.encode("ascii")).hexdigest().upper()
|
|
33
|
+
if not sketch_dir.exists():
|
|
34
|
+
ValueError(f"directory {sketch_dir!r} does not exist.")
|
|
35
|
+
result["DIRECTORY"] = sketch_dir
|
|
36
|
+
NAMES = [f for f in sketch_dir.iterdir() if not f.is_dir() and f.suffix in SUFFIXES and "with_bootloader" not in f.name]
|
|
37
|
+
for name in NAMES:
|
|
38
|
+
result[name.suffix[1:].upper()] = name
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
import sys
|
|
44
|
+
|
|
45
|
+
if len(sys.argv) != 2:
|
|
46
|
+
print("usage: arduino-build-artifacts <sketch-name>")
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
artifacts = build_artifacts(sys.argv[1])
|
|
49
|
+
print()
|
|
50
|
+
for name, value in artifacts.items():
|
|
51
|
+
print(f"{name:9s}: {value}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "objutils"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.2"
|
|
4
4
|
description = "Objectfile library for Python"
|
|
5
5
|
authors = ["Christoph Schueler <cpu12.gems@googlemail.com>"]
|
|
6
6
|
license = "GPLv2"
|
|
@@ -49,6 +49,7 @@ oj-elf-syms = "objutils.scripts.oj_elf_syms:main"
|
|
|
49
49
|
oj-hex-info = "objutils.scripts.oj_hex_info:main"
|
|
50
50
|
oj-elf-arm-attrs = "objutils.scripts.oj_elf_arm_attrs:main"
|
|
51
51
|
oj-elf-extract = "objutils.scripts.oj_elf_extract:main"
|
|
52
|
+
arduino-build-artifacts = "objutils.utils.arduino:main"
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
[tool.poetry.dependencies]
|
|
@@ -63,13 +64,14 @@ prettier = "^0.0.7"
|
|
|
63
64
|
black = "^24.4.1"
|
|
64
65
|
rich = "^13.8.1"
|
|
65
66
|
bandit = "^1.8.2"
|
|
67
|
+
numpy = "<=2.2.5"
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
[tool.poetry.group.dev.dependencies]
|
|
69
71
|
pre-commit = "^3.7.0"
|
|
70
72
|
pytest = "^8.1.1"
|
|
71
73
|
flake8-bugbear = "^24.4.21"
|
|
72
|
-
mccabe = "^0.7.
|
|
74
|
+
mccabe = "^0.7.2"
|
|
73
75
|
pycodestyle = "^2.11.1"
|
|
74
76
|
pyflakes = "^3.2.0"
|
|
75
77
|
ruff = "^0.4.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|