Skip to content

Commit

Permalink
Merge pull request #795 from rohandkn/scalar-default-member
Browse files Browse the repository at this point in the history
Default values for stuct members and scalar initialization of array members
  • Loading branch information
LeStarch authored Jul 2, 2021
2 parents 6fb9830 + 2df0565 commit 5dcbb5c
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 28 deletions.
15 changes: 13 additions & 2 deletions Autocoders/Python/schema/default/serializable_schema.rng
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,19 @@
</attribute>
</optional>

<!-- Type, size, and internal enum define are defined within this ref -->
<ref name="type_size_choice_define"/>
<!-- Optional element -->

<interleave>
<optional>
<a:documentation>Optional default value.</a:documentation>
<element name="default">
<text/>
</element>
</optional>

<!-- Type, size, and internal enum define are defined within this ref -->
<ref name="type_size_choice_define"/>
</interleave>
</element>
</define>
</grammar>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace ${n} {
#end for
#end if
#for ($memname,$type,$size,$format,$comment) in $mem_list:
#for ($memname,$type,$size,$format,$comment,$default) in $mem_list:
#if $type == "string":

${name}::${memname}String::${memname}String(const char* src): StringBase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace ${n} {

class ${name} : public Fw::Serializable {

#for ($memname,$type,$size,$format,$comment) in $mem_list:
#for ($memname,$type,$size,$format,$comment,$default) in $mem_list:
#if $type == "string":

public:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
// public methods

${name}::${name}(void): Serializable() {

#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $default != None and $size != None and $typeinfo != "string":
for (NATIVE_INT_TYPE _mem = 0; _mem < ${size}; _mem++) {
this->m_${member}[_mem] = ${default};
}
#else if $default != None:
this->m_${member} = ${default};
#end if
#end for
}

${name}::${name}(const ${name}& src) : Serializable() {
Expand All @@ -17,21 +25,36 @@ ${name}::${name}(${args_proto_string}) : Serializable() {
this->set(${args_string});
}

#if $args_scalar_array_string:
${name}::${name}(${args_scalar_array_string}) : Serializable() {
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None or $typeinfo == "string":
this->m_${member} = ${member};
#else
for (NATIVE_INT_TYPE _mem = 0; _mem < ${size}; _mem++) {
this->m_${member}[_mem] = ${member};
}
#end if
#end for
}

#end if

const ${name}& ${name}::operator=(const ${name}& src) {
this->set(${args_mstring});
return src;
}

bool ${name}::operator==(const ${name}& src) const {
return (
#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
(src.m_$member == this->m_$member) &&
#end for
true);
}

void ${name}::set(${args_proto_string}) {
#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None or $typeinfo == "string":
this->m_${member} = ${member};
#else
Expand All @@ -42,7 +65,7 @@ void ${name}::set(${args_proto_string}) {
#end for
}

#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None:
${type} ${name}::get${member}(void) const {
return this->m_${member};
Expand All @@ -57,7 +80,7 @@ const ${type}* ${name}::get${member}(NATIVE_INT_TYPE& size) const {
}

#end for
#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None:
void ${name}::set${member}(${type} val) {
this->m_${member} = val;
Expand All @@ -82,7 +105,7 @@ Fw::SerializeStatus ${name}::serialize(Fw::SerializeBufferBase& buffer) const {
stat = buffer.serialize((U32)${name}::TYPE_ID);
\#endif

#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None or $typeinfo == "string":
#if $typeinfo == "enum":
stat = buffer.serialize((FwEnumStoreType)this->m_${member});
Expand Down Expand Up @@ -120,7 +143,7 @@ Fw::SerializeStatus ${name}::deserialize(Fw::SerializeBufferBase& buffer) {
}
\#endif

#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size == None or $typeinfo == "string":
#if $typeinfo == "enum"
FwEnumStoreType int${member} = 0;
Expand Down Expand Up @@ -150,7 +173,7 @@ void ${name}::toString(Fw::StringBase& text) const {

static const char * formatString =
"("
#for ($member,$type,$size,$format,$comment,$typeinfo) in $members[0:-1]:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members[0:-1]:
#if $size != None and typeinfo != "string":
"$member = "
#for $elem in range(0,int($size)-1):
Expand All @@ -174,7 +197,7 @@ void ${name}::toString(Fw::StringBase& text) const {

// declare strings to hold any serializable toString() arguments

#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $typeinfo == "extern":

Fw::EightyCharString ${member}Str;
Expand All @@ -184,7 +207,7 @@ void ${name}::toString(Fw::StringBase& text) const {

char outputString[FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE];
(void)snprintf(outputString,FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE,formatString
#for ($member,$type,$size,$format,$comment,$typeinfo) in $members:
#for ($member,$type,$size,$format,$comment,$default,$typeinfo) in $members:
#if $size != None and $typeinfo != "string":
#for $elem in range(0,int($size)):
#if $type == "bool":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public:
${name}(const ${name}* src); //!< pointer copy constructor
${name}(const ${name}& src); //!< reference copy constructor
${name}($args_proto); //!< constructor with arguments
#if $args_proto_scalar_init:
${name}($args_proto_scalar_init); //!< constructor with arguments with scalars for array arguments
#end if
const ${name}& operator=(const ${name}& src); //!< equal operator
bool operator==(const ${name}& src) const; //!< equality operator
#ifdef BUILD_UT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def _get_args_proto_string(self, obj):
for use in templates that generate prototypes.
"""
arg_str = ""
for (name, mtype, size, format, comment) in obj.get_members():
for (name, mtype, size, format, comment, default) in obj.get_members():
if isinstance(mtype, tuple):
arg_str += "{} {}, ".format(mtype[0][1], name)
elif mtype == "string":
Expand Down Expand Up @@ -128,7 +128,7 @@ def _get_conv_mem_list(self, obj):
"""
arg_list = list()

for (name, mtype, size, format, comment) in obj.get_members():
for (name, mtype, size, format, comment, default) in obj.get_members():
typeinfo = None
if isinstance(mtype, tuple):
mtype = mtype[0][1]
Expand All @@ -139,10 +139,36 @@ def _get_conv_mem_list(self, obj):
elif mtype not in typelist:
typeinfo = "extern"

arg_list.append((name, mtype, size, format, comment, typeinfo))

arg_list.append((name, mtype, size, format, comment, default, typeinfo))
return arg_list

def _get_args_proto_string_scalar_init(self, obj):
"""
Return a string of (type, name) args, comma separated
for use in templates that generate prototypes where the array
arguments are represented by single element values. If no arguments
are arrays, function returns None.
"""
arg_str = ""
contains_array = False
for (name, mtype, size, format, comment, default) in obj.get_members():
if isinstance(mtype, tuple):
arg_str += "{} {}, ".format(mtype[0][1], name)
elif mtype == "string":
arg_str += "const {}::{}String& {}, ".format(obj.get_name(), name, name)
elif mtype not in typelist:
arg_str += "const {}& {}, ".format(mtype, name)
elif size is not None:
arg_str += "const {} {}, ".format(mtype, name)
contains_array = True
else:
arg_str += "{} {}".format(mtype, name)
arg_str += ", "
if not contains_array:
return None
arg_str = arg_str.strip(", ")
return arg_str

def _writeTmpl(self, c, visit_str):
"""
Wrapper to write tmpl to files desc.
Expand Down Expand Up @@ -267,6 +293,7 @@ def publicVisit(self, obj):
c.args_string = self._get_args_string(obj)
c.args_mstring = self._get_args_string(obj, "src.m_")
c.args_mstring_ptr = self._get_args_string(obj, "src->m_")
c.args_scalar_array_string = self._get_args_proto_string_scalar_init(obj)
c.members = self._get_conv_mem_list(obj)
self._writeTmpl(c, "publicVisit")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def _get_args_string(self, obj):
for use in templates that generate prototypes.
"""
arg_str = ""
for (name, mtype, size, format, comment) in obj.get_members():
for (name, mtype, size, format, comment, default) in obj.get_members():
if isinstance(mtype, tuple):
arg_str += "{} {}, ".format(mtype[0][1], name)
elif mtype == "string":
Expand All @@ -105,13 +105,40 @@ def _get_args_string(self, obj):
arg_str = arg_str.strip(", ")
return arg_str

def _get_args_string_scalar_init(self, obj):
"""
Return a string of (type, name) args, comma separated
where array arguments are represented by single element
values for use in templates that generate prototypes.
If no arguments are arrays, function returns None.
"""
arg_str = ""
contains_array = False
for (name, mtype, size, format, comment, default) in obj.get_members():
if isinstance(mtype, tuple):
arg_str += "{} {}, ".format(mtype[0][1], name)
elif mtype == "string":
arg_str += "const {}::{}String& {}, ".format(obj.get_name(), name, name)
elif mtype not in typelist:
arg_str += "const {}& {}, ".format(mtype, name)
elif size is not None:
arg_str += "const {} {}, ".format(mtype, name)
contains_array = True
else:
arg_str += "{} {}".format(mtype, name)
arg_str += ", "
if not contains_array:
return None
arg_str = arg_str.strip(", ")
return arg_str

def _get_conv_mem_list(self, obj):
"""
Return a list of port argument tuples
"""
arg_list = list()

for (name, mtype, size, format, comment) in obj.get_members():
for (name, mtype, size, format, comment, default) in obj.get_members():
typeinfo = None
if isinstance(mtype, tuple):
mtype = mtype[0][1]
Expand Down Expand Up @@ -282,6 +309,7 @@ def publicVisit(self, obj):
c = publicSerialH.publicSerialH()
c.name = obj.get_name()
c.args_proto = self._get_args_string(obj)
c.args_proto_scalar_init = self._get_args_string_scalar_init(obj)
c.members = self._get_conv_mem_list(obj)
self._writeTmpl(c, "publicVisit")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ def __init__(self, xml_file=None):
else:
c = None

d = None

for member_tag in member:
if member_tag.tag == "enum" and t == "ENUM":
en = member_tag.attrib["name"]
Expand All @@ -222,14 +224,16 @@ def __init__(self, xml_file=None):
mc = None
enum_members.append((mn, v, mc))
t = ((t, en), enum_members)
elif member_tag.tag == "default":
d = member_tag.text
else:
PRINT.info(
"%s: Invalid member tag %s in serializable member %s"
% (xml_file, member_tag.tag, n)
)
sys.exit(-1)

self.__members.append((n, t, s, f, c))
self.__members.append((n, t, s, f, c, d))

#
# Generate a type id here using SHA256 algorithm and XML stringified file.
Expand Down
3 changes: 3 additions & 0 deletions Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,15 @@ def check_for_serial_xml(self):
member_size,
member_format_specifier,
member_comment,
member_default,
) in serializable_model.get_members():
member_elem = etree.Element("member")
member_elem.attrib["name"] = member_name
member_elem.attrib["format_specifier"] = member_format_specifier
if member_comment is not None:
member_elem.attrib["description"] = member_comment
if member_default is not None:
member_elem.attrib["default"] = member_default
if isinstance(member_type, tuple):
type_name = "{}::{}::{}".format(
serializable_type,
Expand Down
1 change: 1 addition & 0 deletions Autocoders/Python/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/serialize_user")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/serialize1")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/serialize2")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/serialize3")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/serialize4")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/stress")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/string_port")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/telem_tester")
Expand Down
3 changes: 1 addition & 2 deletions Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
<members>
<member name="Member1" type="U32" comment = "Example member 1"/>
<member name="Member2" type="U32" comment = "Example member 2"/>
<member name="Member3" type="Example::Enum1" comment = "Example enum member">
</member>
<member name="Member3" type="Example::Enum1" comment = "Example enum member"/>
</members>
</serializable>

22 changes: 22 additions & 0 deletions Autocoders/Python/test/serialize4/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ======================================================================
# CMakeLists.txt
# ======================================================================

# We need to declare the XML source files this way to invoke the autocoder.
# However, only the UT build is allowed here.
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/Serial1SerializableAi.xml"
)
register_fprime_module()

# Declare dependencies on test modules
set(UT_MOD_DEPS
Fw/Test
STest
)

# List all .cpp files as UT_SOURCE_FILES. Only the UT build is allowed.
set(UT_SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/main.cpp"
)
register_fprime_ut()
10 changes: 10 additions & 0 deletions Autocoders/Python/test/serialize4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Autocoders/Python/test/serialize4

This directory contains unit tests for the Python serialize XML code generator.

To use this directory, you must have installed F Prime, and you must be inside
the F Prime Python virtual environment.

* To build the tests, run `./build`
* To run the tests, run `./run`
* To run coverage analysis, run `./cov`
Loading

0 comments on commit 5dcbb5c

Please sign in to comment.