wip: idk
This commit is contained in:
parent
675c42cfd5
commit
1812807581
45
py/poetry.lock
generated
45
py/poetry.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
112
py/pytelem/skylab_attr.py
Normal 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
|
||||
|
||||
|
Loading…
Reference in a new issue