This commit is contained in:
saji 2024-01-07 23:01:22 -06:00
parent 675c42cfd5
commit 1812807581
4 changed files with 205 additions and 98 deletions

45
py/poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
[[package]]
name = "aiohttp"
@ -361,6 +361,29 @@ files = [
{file = "boltons-23.0.0.tar.gz", hash = "sha256:8c50a71829525835ca3c849c7ed2511610c972b4dddfcd41a4a5447222beb4b0"},
]
[[package]]
name = "cattrs"
version = "23.2.3"
description = "Composable complex class support for attrs and dataclasses."
optional = false
python-versions = ">=3.8"
files = [
{file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"},
{file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"},
]
[package.dependencies]
attrs = ">=23.1.0"
[package.extras]
bson = ["pymongo (>=4.4.0)"]
cbor2 = ["cbor2 (>=5.4.6)"]
msgpack = ["msgpack (>=1.0.5)"]
orjson = ["orjson (>=3.9.2)"]
pyyaml = ["pyyaml (>=6.0)"]
tomlkit = ["tomlkit (>=0.11.8)"]
ujson = ["ujson (>=5.7.0)"]
[[package]]
name = "certifi"
version = "2023.7.22"
@ -576,6 +599,7 @@ files = [
{file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"},
{file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"},
{file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"},
{file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"},
{file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"},
{file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"},
{file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"},
@ -584,6 +608,7 @@ files = [
{file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"},
{file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"},
{file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"},
{file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"},
{file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"},
{file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"},
{file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"},
@ -592,6 +617,7 @@ files = [
{file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"},
{file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"},
{file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"},
{file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"},
{file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"},
{file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"},
{file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"},
@ -600,6 +626,7 @@ files = [
{file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"},
{file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"},
{file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"},
{file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"},
{file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"},
{file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"},
{file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"},
@ -921,14 +948,17 @@ python-versions = ">=3.6"
files = [
{file = "imgui-bundle-0.8.7.tar.gz", hash = "sha256:546cb787f1e5867abeb87a69870cdb591283a900e74b4c766a1e33b12ac36727"},
{file = "imgui_bundle-0.8.7-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:a47b127bffb4979413f9e6f7d24e9ce115d8440d453facfd4e85329a96bdbde4"},
{file = "imgui_bundle-0.8.7-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:c7a5bafc81fbb9076edd4866a1079f0a8500aef1272be85430e69d536e40721d"},
{file = "imgui_bundle-0.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f277e192d0de34e54bff92194f6f1986a45b220f0f2d9ac8dd04f4ba0a642a"},
{file = "imgui_bundle-0.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d902bad4fc3e9f480eda9fb4a2afa505a31fef9104d02230fed0d38380fb3a32"},
{file = "imgui_bundle-0.8.7-cp310-cp310-win_amd64.whl", hash = "sha256:7ed4bf8aae943d6d84355155d7f256ca37793fe8fe5a96b73273805225023fc6"},
{file = "imgui_bundle-0.8.7-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:6a3f71cf33b3feb4351abab04e5b01e575ca69da429f9ec53c1f76b3d467b4ad"},
{file = "imgui_bundle-0.8.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:ece852a729f01bccaaa0ab18d57c0a953d53acb5ad4c0bb18622deb4f97cfc09"},
{file = "imgui_bundle-0.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d0dfe7913a3a4ea7d7ff443216827be1550fe4a9b5d9310ca68126b5d80fffd"},
{file = "imgui_bundle-0.8.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c5f5e876f85f92ac3d8022a2da7b58604f968ec7fd4122d2f75a79f17818b19c"},
{file = "imgui_bundle-0.8.7-cp311-cp311-win_amd64.whl", hash = "sha256:22fdca289d25d7ddfd5f59ca3c50d612048bc050a305843f110065fe0ad220b7"},
{file = "imgui_bundle-0.8.7-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a93a4b34d12776e7095294e7b0f9e3574174464980300e614e73ed608b6388e6"},
{file = "imgui_bundle-0.8.7-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:0c8c156675158e92fb11d5e5a655256add9b4c494599b414d23d812bc023c96f"},
{file = "imgui_bundle-0.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:628bf02535d417518988d845e81fdb6892257cd7977e19a7c0a1d92d94d1c41a"},
{file = "imgui_bundle-0.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a213811188b2e4fd19e6f9d4e5dd5f5d709e6623b7e2c0a789cc7f300c39c9d"},
{file = "imgui_bundle-0.8.7-cp39-cp39-win_amd64.whl", hash = "sha256:a8612bb86e7993d57b43bfa970e84832eafb81dbeb89c218fe6cb3208ee25ba1"},
@ -1191,6 +1221,7 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
files = [
{file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"},
{file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"},
]
[[package]]
@ -1666,6 +1697,16 @@ files = [
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
{file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@ -3716,4 +3757,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = ">=3.11,<3.12"
content-hash = "f7baee857c94ab620b7ceb3208aab28a5279f36efef8e43a5f49bd35be8f11ec"
content-hash = "7271796b9197f6c2e768e0940faaaca33c62f3d1901a95dd0aae9a0412822bd8"

View file

@ -22,6 +22,8 @@ numba = "^0.57.0"
jax = {extras = ["cpu"], version = "^0.4.12"}
matplotlib = "^3.7.2"
glom = "^23.3.0"
cattrs = "^23.2.3"
attrs = "^23.1.0"
[tool.poetry.group.dev.dependencies]

View file

@ -3,13 +3,31 @@
from abc import ABC, abstractmethod
import re
from pathlib import Path
from typing import Callable, Iterable, NewType, TypedDict, List, Protocol, Union, Set
from typing import Annotated, Callable, Iterable, Literal, NewType, TypedDict, List, Protocol, Union, Set, Optional
from pydantic import field_validator, BaseModel, validator, model_validator
from pydantic.functional_validators import AfterValidator
from enum import Enum
import yaml
import jinja2
def name_valid(s: str) -> str:
if len(s) == 0:
raise ValueError("name cannot be empty string")
if not re.match(r"^[A-Za-z_][A-Za-z0-9_]?$", s):
raise ValueError(f"invalid name: {s}")
return s
# ObjectName is a string that is a valid name, it can only be alphanumeric and underscore.
# it must start with
ObjectName = Annotated[str, AfterValidator(name_valid)]
def is_valid_can_id(i: int) -> int:
if i < 0:
raise ValueError("CAN ID cannot be negative")
return i
CanID = Annotated[int, AfterValidator(is_valid_can_id)]
# This part of the file is dedicated to parsing the skylab yaml files. We define
# classes that represent objects in the yaml files, and perform basic validation on
@ -31,7 +49,6 @@ class FieldType(str, Enum):
I64 = "int64_t"
F32 = "float"
Bitfield = "bitfield"
def size(self) -> int:
"""Returns the size, in bytes, of the type."""
@ -54,8 +71,6 @@ class FieldType(str, Enum):
return 8
case FieldType.F32:
return 4
case FieldType.Bitfield:
return 1
return -1
@ -69,68 +84,43 @@ class _Bits(TypedDict):
name: str
class BitField(BaseModel):
name: ObjectName
type: Literal["bitfield"]
bits: List[_Bits]
class SkylabField(BaseModel):
class EnumField(BaseModel):
name: ObjectName
type: Literal["enum"]
enum_reference: str
"The name of the custom enum to use"
class BasicField(BaseModel):
"""Represents a field (data element) inside a Skylab Packet."""
name: str
"the name of the field. must be alphanumeric and underscores"
name: ObjectName
type: FieldType
"the type of the field"
units: str | None = None
units: Optional[str]
"optional descriptor of the unit representation"
conversion: float | None = None
conversion: Optional[float]
"optional conversion factor to be applied when parsing"
bits: List[_Bits] | None = None
"if the type if a bitfield, "
@model_validator(mode='after')
def bits_must_exist_if_bitfield(self) -> 'SkylabField':
if self.bits is None and self.type == FieldType.Bitfield:
raise ValueError("bits are not present on bitfield type")
if self.bits is not None and self.type != FieldType.Bitfield:
raise ValueError("bits are present on non-bitfield type")
return self
@field_validator("name")
@classmethod
def name_valid_string(cls, v: str) -> str:
if not re.match(r"^[A-Za-z0-9_]+$", v):
raise ValueError("invalid name")
return v
@field_validator("name")
@classmethod
def name_nonzero_length(cls, v: str) -> str:
if len(v) == 0:
raise ValueError("name cannot be empty string")
return v
class Endian(str, Enum):
"""Symbol representing the endianness of the packet"""
Big = "big"
Little = "little"
SkylabField = Union[BasicField, EnumField, BitField]
class SkylabPacket(BaseModel):
"""Represents a CAN packet. Contains SkylabFields with information on the structure of the data."""
name: str
name: ObjectName
description: str | None = None
id: int
endian: Endian
id: CanID
endian: Literal["big", "little"]
repeat: int | None = None
offset: int | None = None
data: List[SkylabField]
# @validator("data")
# def packet_size_limit(cls, v: List[SkylabField]):
# tot = sum([f.type.size() for f in v])
# if tot > 8:
# return ValueError("Total packet size cannot exceed 8 bytes")
# return v
@field_validator("id")
@classmethod
@ -139,34 +129,16 @@ class SkylabPacket(BaseModel):
raise ValueError("id must be above zero")
return v
@field_validator("name")
@classmethod
def name_valid_string(cls, v: str) -> str:
if not re.match(r"^[A-Za-z0-9_]+$", v):
raise ValueError("invalid name", v)
return v
@field_validator("name")
@classmethod
def name_nonzero_length(cls, v: str) -> str:
if len(v) == 0:
raise ValueError("name cannot be empty string")
return v
class RepeatedPacket(BaseModel):
name: ObjectName
description: str | None = None
id: CanID
endian: Literal["big", "little"]
repeat: int
offset: int
data: List[SkylabField]
# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@model_validator(mode='after')
def offset_must_have_repeat(self) -> "SkylabPacket":
if self.offset is not None and self.repeat is not None:
raise ValueError("field with offset must have repeat defined")
return v
@field_validator("repeat")
@classmethod
def repeat_gt_one(cls, v: int | None):
if v is not None and v <= 1:
raise ValueError("repeat must be strictly greater than one")
return v
class SkylabBoard(BaseModel):
@ -177,43 +149,23 @@ class SkylabBoard(BaseModel):
- every name in the transmit/receive list must have a corresponding packet.
"""
name: str
name: ObjectName
"The name of the board"
transmit: List[str]
"The packets sent by this board"
receive: List[str]
"The packets received by this board."
@field_validator("name")
@classmethod
def name_valid_string(cls, v: str):
if not re.match(r"^[A-Za-z0-9_]+$", v):
return ValueError("invalid name", v)
return v
@field_validator("name")
@classmethod
def name_nonzero_length(cls, v: str):
if len(v) == 0:
return ValueError("name cannot be empty string")
return v
class SkylabBus(BaseModel):
name: str
name: ObjectName
"The name of the bus"
baud_rate: int
"Baud rate setting for the bus"
extended_id: bool
"If the bus uses extended ids"
@field_validator("name")
@classmethod
def name_valid_string(cls, v: str):
if not re.match(r"^[A-Za-z0-9_]+$", v):
return ValueError("invalid name", v)
return v
@field_validator("baud_rate")
@classmethod
def baud_rate_supported(cls, v: int):

112
py/pytelem/skylab_attr.py Normal file
View file

@ -0,0 +1,112 @@
from typing import Dict, Optional, List, Union
from enum import Enum
from attrs import define, field, validators
@define
class Bus():
name: str
baud_rate: str
extended_id: bool = False
class FieldType(str, Enum):
"""FieldType indicates the type of the field - the enum represents the C type,
but you can use a map to convert the type to another language."""
# used to ensure types are valid, and act as representations for other languages/mappings.
U8 = "uint8_t"
U16 = "uint16_t"
U32 = "uint32_t"
U64 = "uint64_t"
I8 = "int8_t"
I16 = "int16_t"
I32 = "int32_t"
I64 = "int64_t"
F32 = "float"
Bitfield = "bitfield"
def size(self) -> int:
"""Returns the size, in bytes, of the type."""
match self:
case FieldType.U8:
return 1
case FieldType.U16:
return 2
case FieldType.U32:
return 4
case FieldType.U64:
return 8
case FieldType.I8:
return 1
case FieldType.I16:
return 2
case FieldType.I32:
return 4
case FieldType.I64:
return 8
case FieldType.F32:
return 4
case FieldType.Bitfield:
return 1
return -1
@define
class CustomTypeDef():
name: str
base_type: FieldType # should be a strict size
values: Union[List[str], Dict[str, int]]
@define
class BitfieldBit():
"micro class to represent one bit in bitfields"
name: str
@define
class Field():
name: str = field(validator=[validators.matches_re(r"^[A-Za-z0-9_]+$")])
type: FieldType
#metadata
units: Optional[str]
conversion: Optional[float]
@define
class BitField():
name: str = field(validator=[validators.matches_re(r"^[A-Za-z0-9_]+$")])
type: str = field(default="bitfield", init=False) # it's a constant value
bits: List[BitfieldBit]
class Endian(str, Enum):
BIG = "big"
LITTLE = "little"
@define
class Packet():
name: str
description: str
id: int
endian: Endian
frequency: Optional[int]
data: List[Field]
@define
class RepeatedPacket():
name: str
description: str
id: int
endian: Endian
frequency: Optional[int]
data: List[Field]
repeat: int
offset: int