diff --git a/MANIFEST.in b/MANIFEST.in index 689e50f..1fb9c0d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include LICENSE -include README.md \ No newline at end of file +include README.md +include harp/common.yml \ No newline at end of file diff --git a/harp/common.yml b/harp/common.yml new file mode 100644 index 0000000..4dfd0e6 --- /dev/null +++ b/harp/common.yml @@ -0,0 +1,145 @@ +# yaml-language-server: $schema=registers.json +registers: + WhoAmI: + address: 0 + type: U16 + access: Read + description: Specifies the identity class of the device. + HardwareVersionHigh: + address: 1 + type: U8 + access: Read + description: Specifies the major hardware version of the device. + HardwareVersionLow: + address: 2 + type: U8 + access: Read + description: Specifies the minor hardware version of the device. + AssemblyVersion: + address: 3 + type: U8 + access: Read + description: Specifies the version of the assembled components in the device. + CoreVersionHigh: + address: 4 + type: U8 + access: Read + description: Specifies the major version of the Harp core implemented by the device. + CoreVersionLow: + address: 5 + type: U8 + access: Read + description: Specifies the minor version of the Harp core implemented by the device. + FirmwareVersionHigh: + address: 6 + type: U8 + access: Read + description: Specifies the major version of the Harp core implemented by the device. + FirmwareVersionLow: + address: 7 + type: U8 + access: Read + description: Specifies the minor version of the Harp core implemented by the device. + TimestampSeconds: + address: 8 + type: U32 + access: [Read, Write, Event] + description: Stores the integral part of the system timestamp, in seconds. + volatile: true + TimestampMicroseconds: + address: 9 + type: U16 + access: Read + description: Stores the fractional part of the system timestamp, in microseconds. + volatile: true + OperationControl: + address: 10 + type: U8 + access: Write + description: Stores the configuration mode of the device. + payloadSpec: + OperationMode: + description: Specifies the operation mode of the device. + maskType: OperationMode + mask: 0x3 + DumpRegisters: + description: Specifies whether the device should report the content of all registers on initialization. + interfaceType: bool + mask: 0x8 + MuteReplies: + description: Specifies whether the replies to all commands will be muted, i.e. not sent by the device. + interfaceType: bool + mask: 0x10 + VisualIndicators: + description: Specifies the state of all visual indicators on the device. + maskType: LedState + mask: 0x20 + OperationLed: + description: Specifies whether the device state LED should report the operation mode of the device. + maskType: LedState + mask: 0x40 + Heartbeat: + description: Specifies whether the device should report the content of the seconds register each second. + maskType: EnableFlag + mask: 0x80 + ResetDevice: + address: 11 + type: U8 + access: Write + maskType: ResetFlags + description: Resets the device and saves non-volatile registers. + DeviceName: + address: 12 + type: U8 + length: 25 + access: Write + description: Stores the user-specified device name. + SerialNumber: + address: 13 + type: U16 + access: Write + description: Specifies the unique serial number of the device. + ClockConfiguration: + address: 14 + type: U8 + access: Write + maskType: ClockConfigurationFlags + description: Specifies the configuration for the device synchronization clock. +groupMasks: + OperationMode: + description: Specifies the operation mode of the device. + values: + Standby: 0 + Active: 1 + Speed: 3 + EnableFlag: + description: Specifies whether a specific register flag is enabled or disabled. + values: + Disabled: 0 + Enabled: 1 + LedState: + description: Specifies the state of an LED on the device. + values: + Off: 0 + On: 1 +bitMasks: + ResetFlags: + description: Specifies the behavior of the non-volatile registers when resetting the device. + bits: + None: 0 + RestoreDefault: 0x1 + RestoreEeprom: 0x2 + Save: 0x4 + RestoreName: 0x8 + BootFromDefault: 0x40 + BootFromEeprom: 0x80 + ClockConfigurationFlags: + description: Specifies configuration flags for the device synchronization clock. + bits: + None: 0 + ClockRepeater: 0x1 + ClockGenerator: 0x2 + RepeaterCapability: 0x8 + GeneratorCapability: 0x10 + ClockUnlock: 0x40 + ClockLock: 0x80 \ No newline at end of file diff --git a/harp/model.py b/harp/model.py index 5c5bb3f..879e972 100644 --- a/harp/model.py +++ b/harp/model.py @@ -32,10 +32,14 @@ class MaskValueItem(BaseModel): model_config = ConfigDict( extra='forbid', ) + value: int = Field(..., description='Specifies the numerical mask value.') description: Optional[str] = Field( None, description='Specifies a summary description of the mask value function.' ) + def __int__(self): + return self.value + class MaskValue(RootModel[Union[int, MaskValueItem]]): root: Union[int, MaskValueItem] diff --git a/harp/reader.py b/harp/reader.py index 8aeb5ab..4553bf8 100644 --- a/harp/reader.py +++ b/harp/reader.py @@ -41,7 +41,7 @@ def _id_camel_to_snake(id: str): return _camel_to_snake_regex.sub("_", id).lower() -def _create_bit_parser(mask: Union[int, MaskValueItem]): +def _create_bit_parser(mask: int): def parser(xs: Series) -> Series: return (xs & mask) != 0 @@ -50,7 +50,7 @@ def parser(xs: Series) -> Series: def _create_bitmask_parser(bitMask: BitMask): lookup = [ - (_id_camel_to_snake(k), _create_bit_parser(v.root)) + (_id_camel_to_snake(k), _create_bit_parser(int(v.root))) for k, v in bitMask.bits.items() ] @@ -61,7 +61,7 @@ def parser(df: DataFrame): def _create_groupmask_lookup(groupMask: GroupMask): - return {v.root: n for n, v in groupMask.values.items()} + return {int(v.root): n for n, v in groupMask.values.items()} def _create_groupmask_parser(name: str, groupMask: GroupMask): diff --git a/harp/schema.py b/harp/schema.py new file mode 100644 index 0000000..e28c990 --- /dev/null +++ b/harp/schema.py @@ -0,0 +1,31 @@ +from os import PathLike +from pathlib import Path +from typing import TextIO, Union +from harp.model import Model, Registers +from pydantic_yaml import parse_yaml_raw_as + +_common_yaml_path = Path(__file__).absolute().parent.joinpath("common.yml") + + +def _read_common_registers(file: Union[str, PathLike, TextIO]) -> Registers: + try: + with open(file) as fileIO: + return _read_common_registers(fileIO) + except TypeError: + return parse_yaml_raw_as(Registers, file.read()) + + +def read_schema( + file: Union[str, PathLike, TextIO], include_common_registers: bool = True +) -> Model: + try: + with open(file) as fileIO: + return read_schema(fileIO, include_common_registers) + except TypeError: + schema = parse_yaml_raw_as(Model, file.read()) + if not "WhoAmI" in schema.registers and include_common_registers: + common = _read_common_registers(_common_yaml_path) + schema.registers = dict(common.registers, **schema.registers) + schema.bitMasks = dict(common.bitMasks, **schema.bitMasks) + schema.groupMasks = dict(common.groupMasks, **schema.groupMasks) + return schema