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

Serializable type for Enums #793

Merged
merged 19 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions Autocoders/Python/schema/default/enum_schema.rng
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@

</optional>

<optional>
<attribute name = "serialize_type">
<a:documentation>Serialization type of the enum.</a:documentation>
<text/>
</attribute>

</optional>

<!-- Elements -->
<interleave>
<optional>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,22 @@ a == $item_value#slurp
Fw::SerializeStatus ${name} :: serialize(Fw::SerializeBufferBase& buffer) const
{
Fw::SerializeStatus status;
#if $serialize_type
status = buffer.serialize(static_cast<${serialize_type}>(this->e));
#else
status = buffer.serialize(static_cast<FwEnumStoreType>(this->e));
#end if
return status;
}

Fw::SerializeStatus ${name} :: deserialize(Fw::SerializeBufferBase& buffer)
{
Fw::SerializeStatus status;
#if $serialize_type
${serialize_type} es;
#else
FwEnumStoreType es;
#end if
status = buffer.deserialize(es);
if (status == Fw::FW_SERIALIZE_OK)
this->e = static_cast<t>(es);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ namespace ${namespace} {
// ----------------------------------------------------------------------

enum {
#if $serialize_type
SERIALIZED_SIZE = sizeof(${serialize_type})
#else
SERIALIZED_SIZE = sizeof(FwEnumStoreType)
#end if
};

//! Number of items in ${name} enum
Expand Down
18 changes: 16 additions & 2 deletions Autocoders/Python/src/fprime_ac/parsers/XmlEnumParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(self, xml_file=None):
self.__name = ""
self.__namespace = None
self.__default = None
self.__serialize_type = None

self.__xml_filename = xml_file
self.__items = []
Expand Down Expand Up @@ -107,6 +108,11 @@ def __init__(self, xml_file=None):
else:
self.__default = None

if "serialize_type" in enum.attrib:
self.__serialize_type = enum.attrib["serialize_type"]
else:
self.__serialize_type = None

for enum_tag in enum:
if enum_tag.tag == "item":
item = enum_tag.attrib
Expand Down Expand Up @@ -207,6 +213,9 @@ def get_namespace(self):
def get_default(self):
return self.__default

def get_serialize_type(self):
return self.__serialize_type

def get_items(self):
return self.__items

Expand All @@ -221,8 +230,13 @@ def get_comment(self):
print("Enum XML parse test (%s)" % xmlfile)
xml_parser = XmlEnumParser(xmlfile)
print(
"Enum name: %s, namespace: %s, default: %s"
% (xml_parser.get_name(), xml_parser.get_namespace(), xml_parser.get_default())
"Enum name: %s, namespace: %s, default: %s, serialize_type: %s"
% (
xml_parser.get_name(),
xml_parser.get_namespace(),
xml_parser.get_default(),
xml_parser.get_serialize_type(),
)
)
print("Items")
for item in xml_parser.get_items():
Expand Down
14 changes: 11 additions & 3 deletions Autocoders/Python/src/fprime_ac/utils/EnumGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ def open_file(name, type):
return fp


def write_template(fp, c, name, namespace, default, items, max_value, comment):
def write_template(
fp, c, name, namespace, default, serialize_type, items, max_value, comment
):
"""
Set up and write out templates here
"""
c.name = name
c.namespace = namespace
c.default = default
c.serialize_type = serialize_type
c.items_list = items
c.max_value = max_value
c.comment = comment
Expand All @@ -65,6 +68,7 @@ def generate_enum(xml_file):
name = enum_xml.get_name()
namespace = enum_xml.get_namespace()
default = enum_xml.get_default()
serialize_type = enum_xml.get_serialize_type()
items = enum_xml.get_items()
max_value = enum_xml.get_max_value()
comment = enum_xml.get_comment()
Expand All @@ -73,14 +77,18 @@ def generate_enum(xml_file):
#
fp = open_file(name, "hpp")
c = enum_hpp.enum_hpp()
write_template(fp, c, name, namespace, default, items, max_value, comment)
write_template(
fp, c, name, namespace, default, serialize_type, items, max_value, comment
)
fp.close()
#
# Generate the cpp file
#
fp = open_file(name, "cpp")
c = enum_cpp.enum_cpp()
write_template(fp, c, name, namespace, default, items, max_value, comment)
write_template(
fp, c, name, namespace, default, serialize_type, items, max_value, comment
)
fp.close()
return True
else:
Expand Down
1 change: 1 addition & 0 deletions Autocoders/Python/test/enum_xml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/Component1ComponentAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Enum1EnumAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Enum2EnumAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Enum3EnumAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Port1PortAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Serial1SerializableAi.xml"
)
Expand Down
1 change: 1 addition & 0 deletions Autocoders/Python/test/enum_xml/Component1ComponentAi.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="Component1" kind="active" namespace="Example">
<import_enum_type>Autocoders/Python/test/enum_xml/Enum2EnumAi.xml</import_enum_type>
<import_enum_type>Autocoders/Python/test/enum_xml/Enum3EnumAi.xml</import_enum_type>
<import_port_type>Autocoders/Python/test/enum_xml/Port1PortAi.xml</import_port_type>
<import_serializable_type>Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml</import_serializable_type>
<import_dictionary>Autocoders/Python/test/enum_xml/Telemetry.xml</import_dictionary>
Expand Down
2 changes: 1 addition & 1 deletion Autocoders/Python/test/enum_xml/Enum2EnumAi.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<enum namespace = "Example" name="Enum2">
<enum namespace = "Example" name="Enum2" serialize_type="U64">
<comment>Test enum_xml example enum</comment>
<item name="Item1" value="-1952875139"/>
<item name="Item2" value="2"/>
Expand Down
9 changes: 9 additions & 0 deletions Autocoders/Python/test/enum_xml/Enum3EnumAi.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<enum namespace = "Example" name="Enum3" serialize_type="U8">
<comment>Test enum_xml example enum</comment>
<item name="Item1" value="-1952875139"/>
<item name="Item2" value="2"/>
<item name="Item3" comment="Test Item" value="2000999333"/>
<item name="Item4" value="21"/>
<item name="Item5" value="-8324876"/>
</enum>
28 changes: 28 additions & 0 deletions Autocoders/Python/test/enum_xml/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ TEST(EnumXML, OK) {
Example::Enum1 enum2;
Example::Enum1 enum3;
Example::Enum2 enum4;
Example::Enum3 enum5;

Example::Serial1 serial1;

Expand All @@ -189,6 +190,11 @@ TEST(EnumXML, OK) {
// Check that enum are set to uninitialized value
ASSERT_EQ(enum4.e, 0);

// Check that the enum serializable types are set correctly
ASSERT_EQ(Example::Enum1::SERIALIZED_SIZE, sizeof(FwEnumStoreType));
ASSERT_EQ(Example::Enum2::SERIALIZED_SIZE, sizeof(U64));
ASSERT_EQ(Example::Enum3::SERIALIZED_SIZE, sizeof(U8));

enum1 = getEnumFromI32();
cout << "Created first enum: " << enum1 << endl;

Expand All @@ -209,16 +215,38 @@ TEST(EnumXML, OK) {
// Serialize enums
U8 buffer1[1024];
U8 buffer2[1024];
U8 buffer3[1024];
U8 buffer4[1024];
U8 buffer5[1024];
Fw::SerialBuffer enumSerial1 = Fw::SerialBuffer(buffer1, sizeof(buffer1));
Fw::SerialBuffer enumSerial2 = Fw::SerialBuffer(buffer2, sizeof(buffer2));
Fw::SerialBuffer enumSerial3 = Fw::SerialBuffer(buffer3, sizeof(buffer3));
Fw::SerialBuffer enumSerial4 = Fw::SerialBuffer(buffer4, sizeof(buffer4));
Fw::SerialBuffer enumSerial5 = Fw::SerialBuffer(buffer5, sizeof(buffer5));
ASSERT_EQ(enumSerial1.serialize(enum1), Fw::FW_SERIALIZE_OK);
cout << "Serialized enum1" << endl;

ASSERT_EQ(enumSerial2.serialize(enum2), Fw::FW_SERIALIZE_OK);
cout << "Serialized enum2" << endl;

ASSERT_EQ(enumSerial3.serialize(enum3), Fw::FW_SERIALIZE_OK);
cout << "Serialized enum3" << endl;

ASSERT_EQ(enumSerial4.serialize(enum4), Fw::FW_SERIALIZE_OK);
cout << "Serialized enum4" << endl;

ASSERT_EQ(enumSerial5.serialize(enum5), Fw::FW_SERIALIZE_OK);
cout << "Serialized enum5" << endl;

cout << "Serialized enums" << endl;

// Check that the serialized types are correctly set
ASSERT_EQ(enumSerial1.getBuffLength(), sizeof(FwEnumStoreType));
ASSERT_EQ(enumSerial2.getBuffLength(), sizeof(FwEnumStoreType));
ASSERT_EQ(enumSerial3.getBuffLength(), sizeof(FwEnumStoreType));
ASSERT_EQ(enumSerial4.getBuffLength(), sizeof(U64));
ASSERT_EQ(enumSerial5.getBuffLength(), sizeof(U8));

// Deserialize enums
ASSERT_EQ(enumSerial1.deserialize(enum1Save), Fw::FW_SERIALIZE_OK);
cout << "Deserialized enum1" << endl;
Expand Down
30 changes: 27 additions & 3 deletions docs/UsersGuide/dev/xml-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ types, in port arguments, in telemetry channels, and in event arguments.

As an example, you can create a file `SwitchStateEnumAi.xml` that specifies an
XML enumeration type `SwitchState`
with enumerated constants `OFF` and `ON`, like this:
with enumerated constants `OFF` and `ON` and set to `OFF` by default, like this:

```xml
<enum name="SwitchState">
<enum name="SwitchState" default="OFF">
<item name="OFF" value="0"/>
<item name="ON" value="1"/>
</enum>
Expand Down Expand Up @@ -184,9 +184,22 @@ with attributes *enum_attributes* and children *enum_children*.
of the enumeration type.
The namespace consists of one or more identifiers separated by `::`.

* An optional attribute `default` giving the default value
of the enumeration. This value must match the name attribute of
one of the item definitions within the enumeration (see below).

* An optional attribute `serialize_type` giving the numeric type
of the enumeration when serializing.

If the attribute `namespace` is missing, then the type is
placed in the global namespace.

If the attribute `default` is missing, then the value of the
enumeration is set to 0.

If the attribute `serialize_type` is missing, then the serialization type is
set to FwEnumStoreType.

_Examples:_ Here is an XML enumeration `E` in the global namespace:

`<enum name="E">` ... `</enum>`
Expand All @@ -195,6 +208,17 @@ Here is an XML enumeration `E` in the namespace `A::B`:

`<enum name="E" namespace="A::B">` ... `</enum>`

Here is an XML enumeration `E` in the global namespace with default value Item2
(Item2 is assumed to be the name attribute of one of the item definitions in the enum):

`<enum name="E" default="Item2">` ... `</enum>`


Here is an XML enumeration `E` in the global namespace with serialization type
U64:

`<enum name="E" serialize_type="U64">` ... `</enum>`

**Enum children:**
*enum_children* consists of the following, in any order:

Expand Down Expand Up @@ -826,4 +850,4 @@ in the connections.
The XML specification for the component requires static declaration of
component instances that can be referred to by their object name. If
components are instantiated in other ways such as a heap, the manual
method can be used.
method can be used.