Init Commit: Moved bproto to seperate repo
This commit is contained in:
82
test/reference/python/HCP_protocol_bitfield.py
Normal file
82
test/reference/python/HCP_protocol_bitfield.py
Normal 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 + ")"
|
||||
|
||||
19
test/reference/python/HCP_protocol_enum.py
Normal file
19
test/reference/python/HCP_protocol_enum.py
Normal 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
|
||||
12
test/reference/python/HCP_protocol_message_ids.py
Normal file
12
test/reference/python/HCP_protocol_message_ids.py
Normal 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,
|
||||
}
|
||||
134
test/reference/python/HCP_protocol_packets.py
Normal file
134
test/reference/python/HCP_protocol_packets.py
Normal 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")
|
||||
49
test/reference/txt/protocolSummary.txt
Normal file
49
test/reference/txt/protocolSummary.txt
Normal 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
|
||||
Reference in New Issue
Block a user