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,82 @@
from bproto_base import bproto_Bitfield
class HcpBitfieldEnables(bproto_Bitfield):
BYTE_SIZE = 1
def __init__(self,
a=False,
b=False,
c=False,
):
self.a = a
self.b = b
self.c = c
def to_bytes(self) -> bytes:
res = 0
res |= (1 << 0) if self.a else 0
res |= (1 << 1) if self.b else 0
res |= (1 << 3) if self.c else 0
return int.to_bytes(res, self.BYTE_SIZE, 'little')
def from_bytes(self, data: bytes):
bits = int.from_bytes(data[:self.BYTE_SIZE], 'little')
self.a = (bits & (1 << 0)) != 0
self.b = (bits & (1 << 1)) != 0
self.c = (bits & (1 << 3)) != 0
return self
def __repr__(self) -> str:
value_str = ", ".join([
"a=" + str(self.a),
"b=" + str(self.b),
"c=" + str(self.c),
])
return "HcpBitfieldEnables(" + value_str + ")"
class HcpBitfieldInlineErrorEnables(bproto_Bitfield):
BYTE_SIZE = 1
def __init__(self,
test=False,
asd=False,
b=False,
c=False,
aa=False,
):
self.test = test
self.asd = asd
self.b = b
self.c = c
self.aa = aa
def to_bytes(self) -> bytes:
res = 0
res |= (1 << 0) if self.test else 0
res |= (1 << 1) if self.asd else 0
res |= (1 << 2) if self.b else 0
res |= (1 << 3) if self.c else 0
res |= (1 << 7) if self.aa else 0
return int.to_bytes(res, self.BYTE_SIZE, 'little')
def from_bytes(self, data: bytes):
bits = int.from_bytes(data[:self.BYTE_SIZE], 'little')
self.test = (bits & (1 << 0)) != 0
self.asd = (bits & (1 << 1)) != 0
self.b = (bits & (1 << 2)) != 0
self.c = (bits & (1 << 3)) != 0
self.aa = (bits & (1 << 7)) != 0
return self
def __repr__(self) -> str:
value_str = ", ".join([
"test=" + str(self.test),
"asd=" + str(self.asd),
"b=" + str(self.b),
"c=" + str(self.c),
"aa=" + str(self.aa),
])
return "HcpBitfieldInlineErrorEnables(" + value_str + ")"

View File

@@ -0,0 +1,19 @@
import enum
class HcpEnumErrorCodes(enum.Enum):
MOTOR1_DISCONNECTED = 1
MOTOR2_DISCONNECTED = 2
MOTORS_DISCONNECTED = 3
INPUT_BUFFER_OVERFLOW = 4
class HcpEnumInlineMotionUpdateDangerLvl(enum.Enum):
WARNING = 0
ERROR = 1
MELTDOWN = 2
class HcpEnumInlineErrorRecoveryStatus(enum.Enum):
YES = 0
NO = 1

View File

@@ -0,0 +1,12 @@
import enum
class MessageIds_HCP(enum.Enum):
MSG_ID_HCP_MESSAGE_MOTION_UPDATE = 1
MSG_ID_HCP_MESSAGE_ERROR = 2
MESSAGE_SIZE_MAP_HCP = {
MessageIds_HCP.MSG_ID_HCP_MESSAGE_MOTION_UPDATE: 58,
MessageIds_HCP.MSG_ID_HCP_MESSAGE_ERROR: 5,
}

View File

@@ -0,0 +1,134 @@
from bproto_base import bproto_Package, calc_crc_sum
from bproto_error import bproto_Error, bproto_PackageErrorInvalidSize, bproto_PackageErrorInvalidMessageID, bproto_PackageErrorInvalidCRC
from HCP_protocol_enum import HcpEnumErrorCodes, HcpEnumInlineMotionUpdateDangerLvl, HcpEnumInlineErrorRecoveryStatus
from HCP_protocol_bitfield import HcpBitfieldEnables, HcpBitfieldInlineErrorEnables
from HCP_protocol_message_ids import MessageIds_HCP, MESSAGE_SIZE_MAP_HCP
from typing import Annotated, List
import struct
class HcpMessageMotionUpdate(bproto_Package):
ID = MessageIds_HCP.MSG_ID_HCP_MESSAGE_MOTION_UPDATE
SIZE = 58
speed: Annotated[List[int], 3]
stearing: float
name: str
enable: Annotated[List[bool], 4]
heading: str
enables: HcpBitfieldEnables
danger_lvl: HcpEnumInlineMotionUpdateDangerLvl
def __init__(self,
speed: Annotated[List[int], 3] = 0,
stearing: float = 0.0,
name: str = '',
enable: Annotated[List[bool], 4] = False,
heading: str = '',
enables: HcpBitfieldEnables = HcpBitfieldEnables(),
danger_lvl: HcpEnumInlineMotionUpdateDangerLvl = HcpEnumInlineMotionUpdateDangerLvl.WARNING,
):
self.speed = speed
self.stearing = stearing
self.name = name
self.enable = enable
self.heading = heading
self.enables = enables
self.danger_lvl = danger_lvl
def to_bytes(self) -> bytes:
res = struct.pack(">B", self.ID.value)
res += struct.pack('>iii', self.speed[0], self.speed[1], self.speed[2])
res += struct.pack('>f', self.stearing)
res += self.name.encode('ascii')[:32].ljust(32, b'\x00')
res += struct.pack('>BBBB', self.enable[0], self.enable[1], self.enable[2], self.enable[3])
res += self.heading.encode('ascii')[:1].ljust(1, b'\x00')
res += self.enables.to_bytes()
res += struct.pack('>B', self.danger_lvl.value)
res += calc_crc_sum(res)
return res
def from_bytes(self, data: bytes):
# msg_id = struct.unpack('>B', data[:1])
data = data[1:]
self.speed = list(struct.unpack('>iii', data[:12]))
data = data[12:]
self.stearing = struct.unpack('>f', data[:4])[0]
data = data[4:]
self.name = data[:32].decode('ascii').strip('\x00')
data = data[32:]
self.enable = [bool(i) for i in struct.unpack('>BBBB', data[:4])]
data = data[4:]
self.heading = data[:1].decode('ascii').strip('\x00')
data = data[1:]
self.enables = HcpBitfieldEnables().from_bytes(data[:1])
data = data[1:]
self.danger_lvl = HcpEnumInlineMotionUpdateDangerLvl(struct.unpack('>B', data[:1])[0])
data = data[1:]
# crc = data[:2]
return self
class HcpMessageError(bproto_Package):
ID = MessageIds_HCP.MSG_ID_HCP_MESSAGE_ERROR
SIZE = 5
recovery_status: HcpEnumInlineErrorRecoveryStatus
enables: HcpBitfieldInlineErrorEnables
def __init__(self,
recovery_status: HcpEnumInlineErrorRecoveryStatus = HcpEnumInlineErrorRecoveryStatus.YES,
enables: HcpBitfieldInlineErrorEnables = HcpBitfieldInlineErrorEnables(),
):
self.recovery_status = recovery_status
self.enables = enables
def to_bytes(self) -> bytes:
res = struct.pack(">B", self.ID.value)
res += struct.pack('>B', self.recovery_status.value)
res += self.enables.to_bytes()
res += calc_crc_sum(res)
return res
def from_bytes(self, data: bytes):
# msg_id = struct.unpack('>B', data[:1])
data = data[1:]
self.recovery_status = HcpEnumInlineErrorRecoveryStatus(struct.unpack('>B', data[:1])[0])
data = data[1:]
self.enables = HcpBitfieldInlineErrorEnables().from_bytes(data[:1])
data = data[1:]
# crc = data[:2]
return self
def parse_package(data: bytes) -> tuple[bproto_Package, int]:
if len(data) < 1:
raise bproto_PackageErrorInvalidSize("Package has no data")
msg_id = struct.unpack('>B', data[:1])
if msg_id not in MessageIds_HCP:
raise bproto_PackageErrorInvalidMessageID(f"Message ID '{msg_id}' is invaild")
msg_id = MessageIds_HCP(msg_id)
expected_size = MESSAGE_SIZE_MAP_HCP.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 = pkg_data[-2:]
if calc_crc_sum(pkg_data[:-2]) != crc_data:
raise bproto_PackageErrorInvalidCRC(f"CRC {crc_data.hex()} did not match calculated")
match(msg_id):
case MessageIds_HCP.MSG_ID_HCP_MESSAGE_MOTION_UPDATE:
return HcpMessageMotionUpdate().from_bytes(pkg_data), expected_size
case MessageIds_HCP.MSG_ID_HCP_MESSAGE_ERROR:
return HcpMessageError().from_bytes(pkg_data), expected_size
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,49 @@
Name: Hcp
Version: 0
Enums:
ErrorCodes:
- MOTOR1_DISCONNECTED = 1
- MOTOR2_DISCONNECTED = 2
- MOTORS_DISCONNECTED = 3
- INPUT_BUFFER_OVERFLOW = 4
InlineMotionUpdateDangerLvl:
- WARNING = 0
- ERROR = 1
- MELTDOWN = 2
InlineErrorRecoveryStatus:
- YES = 0
- NO = 1
Bitfield:
Enables:
- a: 0
- b: 1
- c: 3
InlineErrorEnables:
- test: 0
- asd: 1
- b: 2
- c: 3
- aa: 7
Messages:
[1] MotionUpdate:
Size: 55 bytes
Fields:
- (12) speed: int32[3]
- (4) stearing: float32[1]
- (32) name: string[32]
- (4) enable: bool[4]
- (1) heading: char[1]
- (1) enables: bitfield[1] -> Enables
- (1) dangerLvl: enum[1] -> InlineMotionUpdateDangerLvl
[2] Error:
Size: 2 bytes
Fields:
- (1) recoveryStatus: enum[1] -> InlineErrorRecoveryStatus
- (1) enables: bitfield[1] -> InlineErrorEnables