burst-link-protocol 1.1.4__tar.gz → 1.1.5__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.
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.github/workflows/wheel.yml +1 -1
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/PKG-INFO +1 -1
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/pyproject.toml +14 -1
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst_link_protocol/__init__.py +2 -2
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst_link_protocol/main.py +4 -5
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst_link_protocol/serial_burst_interface.py +14 -16
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_burst.py +4 -10
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_burst_decoding.py +8 -3
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_c.py +1 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_c_validation.py +1 -3
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_python_validation.py +5 -4
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/test/test_speed.py +7 -7
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.github/workflows/pip.yml +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.gitignore +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.vscode/c_cpp_properties.json +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.vscode/launch.json +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.vscode/settings.json +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/.vscode/tasks.json +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/CMakeLists.txt +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/LICENSE +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/README.md +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/ROADMAP.md +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/docs/design.drawio +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/docs/design.svg +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_decoder.c +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_decoder.h +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_encoder.c +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_encoder.h +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_generic.c +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst/burst_generic.h +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/burst_link_protocol.h +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/src/python_bindings.cpp +0 -0
- {burst_link_protocol-1.1.4 → burst_link_protocol-1.1.5}/uv.lock +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: burst-link-protocol
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.5
|
4
4
|
Summary: Binary Utility for Reliable Stream Transfer (BURST) is a library for encoding and decoding binary data streams into and from a byte stream.
|
5
5
|
Author-Email: Floris vernieuwe <floris@vernieuwe.eu>
|
6
6
|
License-File: LICENSE
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "burst-link-protocol"
|
3
|
-
version = "1.1.
|
3
|
+
version = "1.1.5" # Choose one version reference here
|
4
4
|
description = "Binary Utility for Reliable Stream Transfer (BURST) is a library for encoding and decoding binary data streams into and from a byte stream."
|
5
5
|
requires-python = ">=3.10,<4.0"
|
6
6
|
authors = [
|
@@ -62,3 +62,16 @@ test-skip="cp38-macosx_*:arm64"
|
|
62
62
|
# Needed for full C++17 support
|
63
63
|
[tool.cibuildwheel.macos.environment]
|
64
64
|
MACOSX_DEPLOYMENT_TARGET = "10.14"
|
65
|
+
|
66
|
+
|
67
|
+
[tool.ruff.lint]
|
68
|
+
select = ["E", "F"]
|
69
|
+
ignore = ["E402"]
|
70
|
+
|
71
|
+
[tool.ruff]
|
72
|
+
line-length = 120
|
73
|
+
exclude = ["**.pyi", "**/.venv/**"]
|
74
|
+
include = ["src/**.py", "test/**.py"]
|
75
|
+
|
76
|
+
[tool.pyright]
|
77
|
+
ignore = ["**.pyi", "**/.venv/**"]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from burst_interface_c import BurstInterfaceC
|
2
2
|
from .main import BurstInterfacePy
|
3
|
-
from .serial_burst_interface import SerialBurstInterface
|
3
|
+
from .serial_burst_interface import SerialBurstInterface, BurstSerialStatistics
|
4
4
|
|
5
|
-
__all__ = ["BurstInterfaceC", "BurstInterfacePy", "SerialBurstInterface"]
|
5
|
+
__all__ = ["BurstInterfaceC", "BurstInterfacePy", "SerialBurstInterface", "BurstSerialStatistics"]
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from cobs import cobs
|
2
|
-
from crc import Calculator,Crc16
|
2
|
+
from crc import Calculator, Crc16
|
3
|
+
|
4
|
+
crc = Calculator(Crc16.IBM_3740) # type: ignore
|
3
5
|
|
4
|
-
crc = Calculator(Crc16.IBM_3740)
|
5
6
|
|
6
7
|
class BurstInterfacePy:
|
7
8
|
buffer = b""
|
@@ -10,9 +11,8 @@ class BurstInterfacePy:
|
|
10
11
|
pass
|
11
12
|
|
12
13
|
@staticmethod
|
13
|
-
def crc16(
|
14
|
+
def crc16(data: bytes) -> bytes:
|
14
15
|
return crc.checksum(data).to_bytes(2, "big")
|
15
|
-
|
16
16
|
|
17
17
|
@staticmethod
|
18
18
|
def encode_packet(packet: bytes) -> bytes:
|
@@ -38,4 +38,3 @@ class BurstInterfacePy:
|
|
38
38
|
# Add last packet to buffer
|
39
39
|
self.buffer = separated_packets.pop()
|
40
40
|
return [self.decode_packet(packet) for packet in separated_packets]
|
41
|
-
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from burst_interface_c import
|
1
|
+
from burst_interface_c import BurstInterfaceC
|
2
2
|
import serial
|
3
3
|
import time
|
4
4
|
import threading
|
@@ -6,6 +6,7 @@ import asyncio
|
|
6
6
|
import janus
|
7
7
|
from pydantic import BaseModel, Field
|
8
8
|
|
9
|
+
|
9
10
|
def to_si(value: float, suffix: str) -> str:
|
10
11
|
"""
|
11
12
|
Convert a value to a string with SI suffix.
|
@@ -34,9 +35,9 @@ class BurstSerialStatistics(BaseModel):
|
|
34
35
|
overflow_errors: int = 0
|
35
36
|
decode_errors: int = 0
|
36
37
|
|
37
|
-
handled_bytes_per_second: float = 0
|
38
|
-
processed_bytes_per_second: float = 0
|
39
|
-
processed_packets_per_second: float = 0
|
38
|
+
handled_bytes_per_second: float = 0.0
|
39
|
+
processed_bytes_per_second: float = 0.0
|
40
|
+
processed_packets_per_second: float = 0.0
|
40
41
|
|
41
42
|
def update(
|
42
43
|
self,
|
@@ -47,21 +48,14 @@ class BurstSerialStatistics(BaseModel):
|
|
47
48
|
overflow_errors,
|
48
49
|
decode_errors,
|
49
50
|
):
|
50
|
-
|
51
51
|
now = time.time()
|
52
52
|
if now - self.last_update_timestamp > 1:
|
53
53
|
delta_time = now - self.last_update_timestamp
|
54
54
|
self.last_update_timestamp = now
|
55
55
|
|
56
|
-
self.handled_bytes_per_second = (
|
57
|
-
|
58
|
-
)
|
59
|
-
self.processed_bytes_per_second = (
|
60
|
-
(bytes_processed - self.bytes_processed) / delta_time
|
61
|
-
)
|
62
|
-
self.processed_packets_per_second = (
|
63
|
-
(packets_processed - self.packets_processed) / delta_time
|
64
|
-
)
|
56
|
+
self.handled_bytes_per_second = (bytes_handled - self.bytes_handled) / delta_time
|
57
|
+
self.processed_bytes_per_second = (bytes_processed - self.bytes_processed) / delta_time
|
58
|
+
self.processed_packets_per_second = (packets_processed - self.packets_processed) / delta_time
|
65
59
|
|
66
60
|
self.bytes_handled = bytes_handled
|
67
61
|
self.bytes_processed = bytes_processed
|
@@ -74,12 +68,16 @@ class BurstSerialStatistics(BaseModel):
|
|
74
68
|
|
75
69
|
def __str__(self):
|
76
70
|
return (
|
77
|
-
f"Byte Raw: {to_si(self.bytes_handled, 'B')} ({to_si(self.handled_bytes_per_second*8, 'bps')}), "
|
78
|
-
f"Bytes processed: {to_si(self.bytes_processed, 'B')} ({to_si(self.processed_bytes_per_second*8, 'bps')}), "
|
71
|
+
f"Byte Raw: {to_si(self.bytes_handled, 'B')} ({to_si(self.handled_bytes_per_second * 8, 'bps')}), "
|
72
|
+
f"Bytes processed: {to_si(self.bytes_processed, 'B')} ({to_si(self.processed_bytes_per_second * 8, 'bps')}), "
|
79
73
|
f"Packets processed: {self.packets_processed} ({to_si(self.processed_packets_per_second, 'packets/s')}), "
|
80
74
|
f"Errors (CRC: {self.crc_errors}, Overflow: {self.overflow_errors}, Decode: {self.decode_errors})"
|
81
75
|
)
|
82
76
|
|
77
|
+
def to_dict(self):
|
78
|
+
return self.model_dump(exclude={"last_update_timestamp"})
|
79
|
+
|
80
|
+
|
83
81
|
class SerialBurstInterface:
|
84
82
|
debug_timings = False
|
85
83
|
debug_io = False
|
@@ -24,7 +24,7 @@ def test_multi_payload():
|
|
24
24
|
# payload = bytes.fromhex("0A 0F 0A 0B 08 80 80 88 50 12 04 26 00 00 00 10 00")
|
25
25
|
for payload in payloads:
|
26
26
|
payload = bytes.fromhex(payload.replace(" ", ""))
|
27
|
-
|
27
|
+
|
28
28
|
if len(payload) < 20:
|
29
29
|
print(f"Testing payload: {payload.hex()}")
|
30
30
|
else:
|
@@ -38,16 +38,10 @@ def test_multi_payload():
|
|
38
38
|
py_decoded_packet = py_interface.decode(c_payload)
|
39
39
|
c_decoded_packet = c_interface.decode(py_payload, fail_on_crc_error=True)
|
40
40
|
|
41
|
-
assert len(c_decoded_packet) == 1, (
|
42
|
-
|
43
|
-
)
|
44
|
-
assert len(py_decoded_packet) == 1, (
|
45
|
-
f"Expected 1 packet, got {len(py_decoded_packet)}"
|
46
|
-
)
|
41
|
+
assert len(c_decoded_packet) == 1, f"Expected 1 packet, got {len(c_decoded_packet)}"
|
42
|
+
assert len(py_decoded_packet) == 1, f"Expected 1 packet, got {len(py_decoded_packet)}"
|
47
43
|
|
48
|
-
assert py_decoded_packet[0] == c_decoded_packet[0],
|
49
|
-
f"Expected {py_decoded_packet}, got {c_decoded_packet}"
|
50
|
-
)
|
44
|
+
assert py_decoded_packet[0] == c_decoded_packet[0], f"Expected {py_decoded_packet}, got {c_decoded_packet}"
|
51
45
|
|
52
46
|
|
53
47
|
if __name__ == "__main__":
|
@@ -2,10 +2,15 @@ from burst_link_protocol import BurstInterfaceC, BurstInterfacePy
|
|
2
2
|
|
3
3
|
payloads = [
|
4
4
|
# Malformed packet
|
5
|
-
(
|
5
|
+
(
|
6
|
+
"04 01 ff 0e 06 d3 23 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 03 85 1f 00 0b 02 04 02 07 02 0b 02 04 02 08 02 0b 02 04 02 0c 02 0b 02 02 02 0d 02 0b 02 02 03 aa 94 00 04 02 ff 0e 03 d3 23 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 03 85 1f 00"
|
7
|
+
)
|
6
8
|
# Good packet
|
7
|
-
(
|
8
|
-
|
9
|
+
(
|
10
|
+
"04 02 ff 0e 03 e1 23 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 03 99 fe 00"
|
11
|
+
)(
|
12
|
+
"04 01 ff 0e 06 ef be ad de c1 02 0b 02 01 02 01 02 0b 02 04 02 02 02 0b 02 04 02 03 02 0b 02 04 02 04 02 0b 02 04 02 05 02 0b 02 04 02 06 02 0b 02 04 02 a6 02 0b 02 04 02 07 02 0b 02 04 02 08 02 0b 02 04 02 0c 02 0b 02 02 02 0d 02 0b 02 02 03 aa 94 00"
|
13
|
+
)
|
9
14
|
]
|
10
15
|
|
11
16
|
|
@@ -31,9 +31,7 @@ def test_python_crc_validation():
|
|
31
31
|
with pytest.raises(Exception):
|
32
32
|
decoded = c_interface.decode(bytes(data_copy), fail_on_crc_error=True)
|
33
33
|
print(decoded)
|
34
|
-
assert len(decoded) == len(packets), (
|
35
|
-
f"Expected {len(packets)} packets, got {len(decoded)}"
|
36
|
-
)
|
34
|
+
assert len(decoded) == len(packets), f"Expected {len(packets)} packets, got {len(decoded)}"
|
37
35
|
|
38
36
|
|
39
37
|
def test_max_size_error():
|
@@ -1,22 +1,23 @@
|
|
1
|
-
|
2
1
|
from burst_link_protocol import BurstInterfacePy
|
3
2
|
import pytest
|
4
3
|
|
4
|
+
|
5
5
|
def test_python():
|
6
|
-
interface =
|
6
|
+
interface = BurstInterfacePy()
|
7
7
|
packets = [b"Hello, world!", b"Goodbye, world!"]
|
8
8
|
|
9
9
|
data = interface.encode(packets)
|
10
10
|
decoded = interface.decode(data)
|
11
11
|
assert packets == decoded
|
12
12
|
|
13
|
+
|
13
14
|
def test_python_crc_validation():
|
14
|
-
interface =
|
15
|
+
interface = BurstInterfacePy()
|
15
16
|
packets = [b"Hello, world!", b"Goodbye, world!"]
|
16
17
|
|
17
18
|
data = bytearray(interface.encode(packets))
|
18
19
|
|
19
|
-
for i in range(
|
20
|
+
for i in range(len(data)):
|
20
21
|
data_copy = data.copy()
|
21
22
|
|
22
23
|
# modify byte x
|
@@ -1,20 +1,20 @@
|
|
1
|
-
|
2
|
-
from burst_link_protocol import BurstInterfacePy,BurstInterfaceC
|
1
|
+
from burst_link_protocol import BurstInterfacePy, BurstInterfaceC
|
3
2
|
import pytest
|
4
3
|
import numpy as np
|
5
4
|
|
6
|
-
def prepare_packets(packet_size:int) -> bytes:
|
7
|
-
python_interface = BurstInterfacePy()
|
8
|
-
return python_interface.encode([np.zeros(packet_size).tobytes()])
|
9
5
|
|
6
|
+
def prepare_packets(packet_size: int) -> bytes:
|
7
|
+
python_interface = BurstInterfacePy()
|
8
|
+
return python_interface.encode([np.zeros(packet_size).tobytes()])
|
10
9
|
|
11
10
|
|
12
11
|
@pytest.mark.parametrize("n", [1, 10, 100, 1000])
|
13
12
|
def test_performance_c(benchmark, n):
|
14
|
-
c_interface =
|
13
|
+
c_interface = BurstInterfaceC()
|
15
14
|
benchmark(c_interface.decode, prepare_packets(n))
|
16
15
|
|
16
|
+
|
17
17
|
@pytest.mark.parametrize("n", [1, 10, 100, 1000])
|
18
18
|
def test_performance_python(benchmark, n):
|
19
|
-
c_interface =
|
19
|
+
c_interface = BurstInterfacePy()
|
20
20
|
benchmark(c_interface.decode, prepare_packets(n))
|
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
|