Init Commit: Moved bproto to seperate repo

This commit is contained in:
AlexanderHD27
2025-04-14 14:43:03 +02:00
commit 45bfc724fc
125 changed files with 10822 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
import abc
class bproto_Package(abc.ABC):
@abc.abstractmethod
def to_bytes(self) -> bytes:
raise NotImplementedError()
@abc.abstractmethod
def from_bytes(self, data: bytes):
raise NotImplementedError()
class bproto_Bitfield(abc.ABC):
@abc.abstractmethod
def to_bytes(self) -> bytes:
pass
@abc.abstractmethod
def from_bytes(self, data: bytes):
pass
def __str__(self):
return self.__repr__()
def crc16_calc_inital(data: bytearray) -> int:
"""CRC-16/CITT-FALSE
from https://stackoverflow.com/questions/35205702/calculating-crc16-in-python
Args:
data (bytearray): protocol hash
Returns:
bytes: initals for crc16_calc_with_initial
"""
crc = 0xFFFF
for i in range(0, len(data)):
crc ^= data[i] << 8
for j in range(0, 8):
if (crc & 0x8000) > 0:
crc = (crc << 1) ^ 0x1021
else:
crc = crc << 1
return crc
def calc_crc_sum(data: bytearray, inital: int) -> bytes:
"""CRC-16/CITT-FALSE
form https://stackoverflow.com/questions/35205702/calculating-crc16-in-python
Args:
data (bytearray): protocol data
inital (int): Inital calculated from protocol hash
Returns:
bytes: 2 byte CRC Checksum
"""
crc = inital
for i in range(0, len(data)):
crc ^= data[i] << 8
for j in range(0, 8):
if (crc & 0x8000) > 0:
crc = (crc << 1) ^ 0x1021
else:
crc = crc << 1
return crc & 0xFFFF

View File

@@ -0,0 +1,19 @@
class bproto_Error(Exception):
def __init__(self, message):
self.message = message
class bproto_PackageError(bproto_Error):
pass
class bproto_PackageErrorInvalidSize(bproto_PackageError):
pass
class bproto_PackageErrorInvalidMessageID(bproto_PackageError):
pass
class bproto_PackageErrorInvalidCRC(bproto_PackageError):
pass

View File

@@ -0,0 +1,38 @@
from bproto_base import bproto_Bitfield
{% for bitfield in bitfields %}
class {{bitfield.name}}(bproto_Bitfield):
BYTE_SIZE = {{bitfield.size}}
def __init__(self,
{%- for bit in bitfield.bits %}
{{bit.name}}=False,
{%- endfor %}
):
{%- for bit in bitfield.bits %}
self.{{bit.name}} = {{bit.name}}
{%- endfor %}
def to_bytes(self) -> bytes:
res = 0
{%- for bit in bitfield.bits %}
res |= (1 << {{bit.pos}}) if self.{{bit.name}} else 0
{%- endfor %}
return int.to_bytes(res, self.BYTE_SIZE, '{{protocol.endian_str}}')
def from_bytes(self, data: bytes):
bits = int.from_bytes(data[:self.BYTE_SIZE], '{{protocol.endian_str}}')
{%- for bit in bitfield.bits %}
self.{{bit.name}} = (bits & (1 << {{bit.pos}})) != 0
{%- endfor %}
return self
def __repr__(self) -> str:
value_str = ", ".join([
{%- for bit in bitfield.bits %}
"{{bit.name}}=" + str(self.{{bit.name}}),
{%- endfor %}
])
return "{{bitfield.name}}(" + value_str + ")"
{% endfor %}

View File

@@ -0,0 +1,19 @@
from bproto_base import bproto_Package, calc_crc_sum
from bproto_error import bproto_Error, bproto_PackageErrorInvalidSize, bproto_PackageErrorInvalidMessageID, bproto_PackageErrorInvalidCRC
from {{ import_name }}_protocol_enum import {% for e in enums %}{{e.name}}{% if not loop.last %}, {% endif %}{% endfor %}
from {{ import_name }}_protocol_bitfield import {% for b in bitfields %}{{b.name}}{% if not loop.last %}, {% endif %}{% endfor %}
from {{ import_name }}_protocol_message_ids import MessageIds_{{ protocol.name }}, MESSAGE_SIZE_MAP_{{ protocol.name }}
from typing import Annotated, List
import struct
CRC_INITAL = {{ protocol.crc_initial }}
{% for m in messages %}
{%- include 'python/template/message/class.jinja2' -%}
{%- if not loop.last %}
{% else %}{%- endif -%}{%- endfor %}
{% include 'python/template/message/parse_generic.jinja2' -%}

View File

@@ -0,0 +1,15 @@
import enum
class MessageIds_{{ protocol.name }}(enum.Enum):
{%- for msg in messages %}
{{ msg.id_name }} = {{ msg.id }}
{%- endfor %}
MESSAGE_SIZE_MAP_{{ protocol.name }} = {
{%- for msg in messages %}
MessageIds_{{ protocol.name }}.{{ msg.id_name }}: {{ msg.size }},
{%- endfor %}
}

View File

@@ -0,0 +1,8 @@
import enum
{% for e in enums %}
class {{ e.name }}(enum.Enum):
{%- for k,v in e.consts %}
{{ k }} = {{ v }}
{%- endfor %}
{% endfor %}

View File

@@ -0,0 +1,20 @@
class {{m.name}}(bproto_Package):
ID = MessageIds_{{ protocol.name }}.{{m.id_name}}
SIZE = {{ m.size }}
{% for f in m.fields %}
{{f.name}}: {{f.type}}
{%- endfor %}
def __init__(self,
{% for f in m.fields -%}
{{f.name}}: {{f.type}} = {{f.default_value}},
{% endfor -%}
):
{% for f in m.fields -%}
self.{{f.name}} = {{f.name}}
{% endfor -%}
{% include 'python/template/message/toBytes.jinja2' %}
{% include 'python/template/message/fromBytes.jinja2' %}

View File

@@ -0,0 +1,21 @@
def from_bytes(self, data: bytes):
if len(data) < self.SIZE:
raise bproto_PackageErrorInvalidSize(f"A size of {len(data)} is to small for {{ protocol.name }} (min. {self.SIZE})")
msg_id = struct.unpack('{{protocol.endian_format}}B', data[:1])[0]
crc_data = struct.unpack('{{protocol.endian_format}}H', data[-{{ protocol.crc_size }}:])[0]
if calc_crc_sum(data[:-{{ protocol.crc_size }}], CRC_INITAL) != crc_data:
raise bproto_PackageErrorInvalidCRC(f"CRC {crc_data:04x} did not match calculated")
if msg_id != self.ID.value:
raise bproto_PackageErrorInvalidMessageID("Message ID {msd_id} does not match {{ protocol.name }}'s id {self.ID.value}")
data = data[1:]
{% for f in m.fields -%}
self.{{ f.name }} = {{ f.from_bytes_conversion }}
data = data[{{ f.size }}:]
{% endfor -%}
return self

View File

@@ -0,0 +1,31 @@
def parse_package(data: bytes) -> tuple[bproto_Package, int]:
if len(data) < 1:
raise bproto_PackageErrorInvalidSize("Package has no data")
msg_id = struct.unpack('{{protocol.endian_format}}B', data[:1])[0]
if msg_id not in MessageIds_{{ protocol.name }}:
raise bproto_PackageErrorInvalidMessageID(f"Message ID '{msg_id}' is invaild")
msg_id = MessageIds_{{ protocol.name }}(msg_id)
expected_size = MESSAGE_SIZE_MAP_{{ protocol.name }}.get(msg_id) or 0
if expected_size > len(data):
raise bproto_PackageErrorInvalidSize(f"Package is to short for '{msg_id}' ({expected_size} > {len(data)})")
pkg_data = data[:expected_size]
crc_data = struct.unpack('{{protocol.endian_format}}H', pkg_data[-2:])[0]
if calc_crc_sum(pkg_data[:-2], CRC_INITAL) != crc_data:
raise bproto_PackageErrorInvalidCRC(f"CRC {crc_data:04x} did not match calculated")
match(msg_id):
{%- for msg in messages %}
case MessageIds_{{ protocol.name }}.{{ msg.id_name }}:
return {{msg.name}}().from_bytes(pkg_data), expected_size
{%- endfor %}
case _:
raise bproto_Error("Message ID could not be interpreted; this should not have happen; its a developer error! Create a issue")

View File

@@ -0,0 +1,8 @@
def to_bytes(self) -> bytes:
res = struct.pack("{{protocol.endian_format}}B", self.ID.value)
{% for f in m.fields -%}
res += {{ f.to_bytes_conversion }}
{% endfor -%}
res += struct.pack("{{protocol.endian_format}}H", calc_crc_sum(res, CRC_INITAL))
return res