Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/enum representation types #184

Merged
merged 13 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/actions/spelling/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ calcsize
changelog
chdir
classmethod
Endian
endian
Endianness
endianness
lestarch
LGTM
lgtm
Expand Down
42 changes: 34 additions & 8 deletions src/fprime/common/models/serialize/enum_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import struct

from .type_base import DictionaryType
from .fprime_integer_metadata import FPRIME_INTEGER_METADATA
from .type_exceptions import (
DeserializeException,
EnumMismatchException,
NotInitializedException,
TypeMismatchException,
TypeRangeException,
InvalidRepresentationTypeException,
RepresentationTypeRangeException,
)


Expand All @@ -24,14 +27,15 @@ class EnumType(DictionaryType):
"""

@classmethod
def construct_type(cls, name, enum_dict):
def construct_type(cls, name, enum_dict, rep_type="I32"):
"""Construct the custom enum type

Constructs the custom enumeration type, with the supplied enumeration dictionary.

Args:
name: name of the enumeration type
enum_dict: enumeration: value dictionary defining the enumeration
rep_type: representation type (standard Fprime integer types)
"""
if not isinstance(enum_dict, dict):
raise TypeMismatchException(dict, type(enum_dict))
Expand All @@ -40,7 +44,22 @@ def construct_type(cls, name, enum_dict):
raise TypeMismatchException(str, type(member))
if not isinstance(enum_dict[member], int):
raise TypeMismatchException(int, enum_dict[member])
return DictionaryType.construct_type(cls, name, ENUM_DICT=enum_dict)

if rep_type not in FPRIME_INTEGER_METADATA.keys():
raise InvalidRepresentationTypeException(rep_type)

for member in enum_dict.keys():
if (
enum_dict[member] < FPRIME_INTEGER_METADATA[rep_type]["min"]
or enum_dict[member] > FPRIME_INTEGER_METADATA[rep_type]["max"]
):
raise RepresentationTypeRangeException(
member, enum_dict[member], rep_type
)

return DictionaryType.construct_type(
cls, name, ENUM_DICT=enum_dict, REP_TYPE=rep_type
)

@classmethod
def validate(cls, val):
Expand All @@ -67,14 +86,20 @@ def serialize(self):
self._val == "UNDEFINED" and "UNDEFINED" not in self.ENUM_DICT
):
raise NotInitializedException(type(self))
return struct.pack(">i", self.ENUM_DICT[self._val])
return struct.pack(
FPRIME_INTEGER_METADATA[self.REP_TYPE]["struct_formatter"],
self.ENUM_DICT[self._val],
)

def deserialize(self, data, offset):
"""
Deserialize the enumeration using an int type
"""
try:
int_val = struct.unpack_from(">i", data, offset)[0]
int_val = struct.unpack_from(
FPRIME_INTEGER_METADATA[self.REP_TYPE]["struct_formatter"], data, offset
)[0]

except struct.error:
msg = f"Could not deserialize enum value. Needed: {self.getSize()} bytes Found: {len(data[offset:])}"
raise DeserializeException(msg)
Expand All @@ -86,12 +111,13 @@ def deserialize(self, data, offset):
else:
raise TypeRangeException(int_val)

@classmethod
def getSize(cls):
def getSize(self):
"""Calculates the size based on the size of an integer used to store it"""
return struct.calcsize(">i")
return struct.calcsize(
FPRIME_INTEGER_METADATA[self.REP_TYPE]["struct_formatter"]
)

@classmethod
def getMaxSize(cls):
"""Maximum size of type"""
return cls.getSize() # Always the same as getSize
return struct.calcsize(FPRIME_INTEGER_METADATA["U64"]["struct_formatter"])
LeStarch marked this conversation as resolved.
Show resolved Hide resolved
24 changes: 24 additions & 0 deletions src/fprime/common/models/serialize/fprime_integer_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Created on Aug 29, 2023
@author: Jack White
"""

"""
Key is the F prime integer type as a string; value is the struct library
formatter for that type. Note that the big-Endian formatter '>' ensures
the width of the read or write.
"""
FPRIME_INTEGER_METADATA = {
"U8": {"struct_formatter": ">B", "min": 0, "max": 255},
"U16": {"struct_formatter": ">H", "min": 0, "max": 65535},
"U32": {"struct_formatter": ">I", "min": 0, "max": 4294967295},
"U64": {"struct_formatter": ">Q", "min": 0, "max": 18446744073709551615},
"I8": {"struct_formatter": ">b", "min": -128, "max": 127},
"I16": {"struct_formatter": ">h", "min": -32768, "max": 32767},
"I32": {"struct_formatter": ">i", "min": -2147483648, "max": 2147483647},
"I64": {
"struct_formatter": ">q",
"min": -9223372036854775808,
"max": 9223372036854775807,
},
}
25 changes: 25 additions & 0 deletions src/fprime/common/models/serialize/type_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Exception classes for all types
from fprime.common.error import FprimeException
from .fprime_integer_metadata import FPRIME_INTEGER_METADATA


class TypeException(FprimeException):
Expand Down Expand Up @@ -126,3 +127,27 @@ def __init__(self, field_length_actual, field_length_given):
"%d fields provided, but compound type expects %d fields!"
% (field_length_given, field_length_actual)
)


class InvalidRepresentationTypeException(TypeException):
"""Representation type of the given enumeration is not an F prime integer type"""

def __init__(self, given_rep_type):
super().__init__(
"Representation type {} not found in F prime types ({})"
).format(given_rep_type, str(FPRIME_INTEGER_METADATA.keys()))


class RepresentationTypeRangeException(TypeException):
"""Enumeration member is out of range of the representation type"""

def __init__(self, key, value, given_rep_type):
super().__init__(
"Enumeration member {} with value {} is out of range of representation type {} ({}-{})".format(
key,
value,
given_rep_type,
FPRIME_INTEGER_METADATA[given_rep_type]["min"],
FPRIME_INTEGER_METADATA[given_rep_type]["max"],
)
)
Loading