msg ROS2 compatibility, microdds_client improvements (timesync, reduced code size, added topics, etc), fastrtps purge

- update all msgs to be directly compatible with ROS2
 - microdds_client improvements
   - timesync
   - reduced code size
   - add to most default builds if we can afford it
   - lots of other little changes
 - purge fastrtps (I tried to save this multiple times, but kept hitting roadblocks)
This commit is contained in:
Daniel Agar
2022-10-19 19:36:47 -04:00
committed by GitHub
parent e211e0ca0e
commit cea185268e
318 changed files with 1948 additions and 8939 deletions
View File
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""
Generate docs from .msg files
"""
import os
import argparse
import sys
def get_msgs_list(msgdir):
"""
Makes list of msg files in the given directory
"""
return [fn for fn in os.listdir(msgdir) if fn.endswith(".msg")]
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generate docs from .msg files')
parser.add_argument('-d', dest='dir', help='output directory', required=True)
args = parser.parse_args()
output_dir = args.dir
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
msg_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"..")
msg_files = get_msgs_list(msg_path)
msg_files.sort()
filelist_in_markdown=''
for msg_file in msg_files:
msg_name = os.path.splitext(msg_file)[0]
output_file = os.path.join(output_dir, msg_name+'.md')
msg_filename = os.path.join(msg_path, msg_file)
print("{:} -> {:}".format(msg_filename, output_file))
#Format msg url
msg_url="[source file](https://github.com/PX4/PX4-Autopilot/blob/main/msg/%s)" % msg_file
msg_description = ""
summary_description = ""
#Get msg description (first non-empty comment line from top of msg)
with open(msg_filename, 'r') as lineparser:
line = lineparser.readline()
while line.startswith('#') or (line.strip() == ''):
print('DEBUG: line: %s' % line)
line=line[1:].strip()+'\n'
stripped_line=line.strip()
if msg_description and not summary_description and stripped_line=='':
summary_description = msg_description.strip()
msg_description+=line
line = lineparser.readline()
msg_description=msg_description.strip()
if not summary_description and msg_description:
summary_description = msg_description
print('msg_description: Z%sZ' % msg_description)
print('summary_description: Z%sZ' % summary_description)
summary_description
msg_contents = ""
#Get msg contents (read the file)
with open(msg_filename, 'r') as source_file:
msg_contents = source_file.read()
#Format markdown using msg name, comment, url, contents.
markdown_output="""# %s (UORB message)
%s
%s
```c
%s
```
""" % (msg_name, msg_description, msg_url, msg_contents)
with open(output_file, 'w') as content_file:
content_file.write(markdown_output)
readme_markdown_file_link='- [%s](%s.md)' % (msg_name,msg_name)
if summary_description:
readme_markdown_file_link+="%s" % summary_description
filelist_in_markdown+=readme_markdown_file_link+"\n"
# Write out the README.md file
readme_text="""# uORB Message Reference
:::note
This list is [auto-generated](https://github.com/PX4/PX4-Autopilot/blob/main/Tools/msg/generate_msg_docs.py) from the source code.
:::
This topic lists the UORB messages available in PX4 (some of which may be may be shared by the [PX4-ROS 2 Bridge](../ros/ros2_comm.md)).
Graphs showing how these are used [can be found here](../middleware/uorb_graph.md).
%s
""" % (filelist_in_markdown)
readme_file = os.path.join(output_dir, 'README.md')
with open(readme_file, 'w') as content_file:
content_file.write(readme_text)
+253
View File
@@ -0,0 +1,253 @@
#!/usr/bin/env python3
#############################################################################
#
# Copyright (C) 2013-2022 PX4 Pro Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#############################################################################
"""
px_generate_uorb_topic_files.py
Generates c/cpp header/source files for uorb topics from .msg
message files
"""
import os
import argparse
import re
import sys
try:
import em
except ImportError as e:
print("Failed to import em: " + str(e))
print("")
print("You may need to install it using:")
print(" pip3 install --user empy")
print("")
sys.exit(1)
try:
import genmsg.template_tools
except ImportError as e:
print("Failed to import genmsg: " + str(e))
print("")
print("You may need to install it using:")
print(" pip3 install --user pyros-genmsg")
print("")
sys.exit(1)
__author__ = "Sergey Belash, Thomas Gubler, Beat Kueng"
__copyright__ = "Copyright (C) 2013-2022 PX4 Development Team."
__license__ = "BSD"
__email__ = "thomasgubler@gmail.com"
TEMPLATE_FILE = ['msg.h.em', 'msg.cpp.em']
TOPICS_LIST_TEMPLATE_FILE = ['uORBTopics.hpp.em', 'uORBTopics.cpp.em']
OUTPUT_FILE_EXT = ['.h', '.cpp']
INCL_DEFAULT = ['std_msgs:./msg/std_msgs']
PACKAGE = 'px4'
TOPICS_TOKEN = '# TOPICS '
def get_topics(filename):
"""
Get TOPICS names from a "# TOPICS" line
"""
ofile = open(filename, 'r')
text = ofile.read()
result = []
for each_line in text.split('\n'):
if each_line.startswith(TOPICS_TOKEN):
topic_names_str = each_line.strip()
topic_names_str = topic_names_str.replace(TOPICS_TOKEN, "")
topic_names_list = topic_names_str.split(" ")
for topic in topic_names_list:
# topic name PascalCase (file name) to snake_case (topic name)
topic_name = re.sub(r'(?<!^)(?=[A-Z])', '_', topic).lower()
result.append(topic_name)
ofile.close()
if len(result) == 0:
# topic name PascalCase (file name) to snake_case (topic name)
file_base_name = os.path.basename(filename).replace(".msg", "")
topic_name = re.sub(r'(?<!^)(?=[A-Z])', '_', file_base_name).lower()
result.append(topic_name)
return result
def generate_output_from_file(format_idx, filename, outputdir, package, templatedir, includepath):
"""
Converts a single .msg file to an uorb header/source file
"""
msg_context = genmsg.msg_loader.MsgContext.create_default()
full_type_name = genmsg.gentools.compute_full_type_name(package, os.path.basename(filename))
file_base_name = os.path.basename(filename).replace(".msg", "")
full_type_name_snake = re.sub(r'(?<!^)(?=[A-Z])', '_', file_base_name).lower()
spec = genmsg.msg_loader.load_msg_from_file(msg_context, filename, full_type_name)
field_name_and_type = {}
for field in spec.parsed_fields():
field_name_and_type.update({field.name: field.type})
# assert if the timestamp field exists
try:
assert 'timestamp' in field_name_and_type
except AssertionError:
print("[ERROR] uORB topic files generator:\n\tgenerate_output_from_file:\tNo 'timestamp' field found in " +
spec.short_name + " msg definition!")
exit(1)
# assert if the timestamp field is of type uint64
try:
assert field_name_and_type.get('timestamp') == 'uint64'
except AssertionError:
print("[ERROR] uORB topic files generator:\n\tgenerate_output_from_file:\t'timestamp' field in " + spec.short_name +
" msg definition is not of type uint64 but rather of type " + field_name_and_type.get('timestamp') + "!")
exit(1)
topics = get_topics(filename)
if includepath:
search_path = genmsg.command_line.includepath_to_dict(includepath)
else:
search_path = {}
genmsg.msg_loader.load_depends(msg_context, spec, search_path)
em_globals = {
"name_snake_case": full_type_name_snake,
"file_name_in": filename,
"search_path": search_path,
"msg_context": msg_context,
"spec": spec,
"topics": topics,
}
# Make sure output directory exists:
if not os.path.isdir(outputdir):
os.makedirs(outputdir)
template_file = os.path.join(templatedir, TEMPLATE_FILE[format_idx])
output_file = os.path.join(outputdir, full_type_name_snake + OUTPUT_FILE_EXT[format_idx])
return generate_by_template(output_file, template_file, em_globals)
def generate_by_template(output_file, template_file, em_globals):
"""
Invokes empy intepreter to geneate output_file by the
given template_file and predefined em_globals dict
"""
# check if folder exists:
folder_name = os.path.dirname(output_file)
if not os.path.exists(folder_name):
os.makedirs(folder_name)
ofile = open(output_file, 'w')
# todo, reuse interpreter
interpreter = em.Interpreter(output=ofile, globals=em_globals, options={
em.RAW_OPT: True, em.BUFFERED_OPT: True})
try:
interpreter.file(open(template_file))
except OSError as e:
ofile.close()
os.remove(output_file)
raise
interpreter.shutdown()
ofile.close()
return True
def generate_topics_list_file_from_files(files, outputdir, template_filename, templatedir):
# generate cpp file with topics list
filenames = []
for filename in [os.path.basename(p) for p in files if os.path.basename(p).endswith(".msg")]:
filenames.append(re.sub(r'(?<!^)(?=[A-Z])', '_', filename).lower())
topics = []
for msg_filename in files:
topics.extend(get_topics(msg_filename))
tl_globals = {"msgs": filenames, "topics": topics}
tl_template_file = os.path.join(templatedir, template_filename)
tl_out_file = os.path.join(outputdir, template_filename.replace(".em", ""))
generate_by_template(tl_out_file, tl_template_file, tl_globals)
def append_to_include_path(path_to_append, curr_include, package):
for p in path_to_append:
curr_include.append('%s:%s' % (package, p))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert msg files to uorb headers/sources')
parser.add_argument('--headers', help='Generate header files', action='store_true')
parser.add_argument('--sources', help='Generate source files', action='store_true')
parser.add_argument('-f', dest='file',
help="files to convert (use only without -d)",
nargs="+")
parser.add_argument('-i', dest="include_paths",
help='Additional Include Paths', nargs="*",
default=None)
parser.add_argument('-e', dest='templatedir',
help='directory with template files',)
parser.add_argument('-k', dest='package', default=PACKAGE,
help='package name')
parser.add_argument('-o', dest='outputdir',
help='output directory for header files')
parser.add_argument('-p', dest='prefix', default='',
help='string added as prefix to the output file '
' name when converting directories')
args = parser.parse_args()
if args.include_paths:
append_to_include_path(args.include_paths, INCL_DEFAULT, args.package)
if args.headers:
generate_idx = 0
elif args.sources:
generate_idx = 1
else:
print('Error: either --headers or --sources must be specified')
exit(-1)
if args.file is not None:
for f in args.file:
generate_output_from_file(generate_idx, f, args.outputdir, args.package, args.templatedir, INCL_DEFAULT)
# Generate topics list header and source file
if os.path.isfile(os.path.join(args.templatedir, TOPICS_LIST_TEMPLATE_FILE[generate_idx])):
generate_topics_list_file_from_files(args.file, args.outputdir, TOPICS_LIST_TEMPLATE_FILE[generate_idx], args.templatedir)
+288
View File
@@ -0,0 +1,288 @@
#!/usr/bin/env python3
#############################################################################
#
# Copyright (C) 2013-2022 PX4 Pro Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#############################################################################
'''
Helper methods & common code for the uorb message templates msg.{cpp,h}.em
Another positive effect of having the code here, is that this file will get
precompiled and thus message generation will be much faster
'''
import os
import errno
import re
import genmsg.msgs
type_map = {
'int8': 'int8_t',
'int16': 'int16_t',
'int32': 'int32_t',
'int64': 'int64_t',
'uint8': 'uint8_t',
'uint16': 'uint16_t',
'uint32': 'uint32_t',
'uint64': 'uint64_t',
'float32': 'float',
'float64': 'double',
'bool': 'bool',
'char': 'char',
}
type_map_short = {
# We use some range outside of alpha-numeric and special characters.
# This needs to match with orb_get_c_type()
'int8': '\\x82',
'int16': '\\x83',
'int32': '\\x84',
'int64': '\\x85',
'uint8': '\\x86',
'uint16': '\\x87',
'uint32': '\\x88',
'uint64': '\\x89',
'float32': '\\x8a',
'float64': '\\x8b',
'bool': '\\x8c',
'char': '\\x8d',
}
type_serialize_map = {
'int8': 'int8_t',
'int16': 'int16_t',
'int32': 'int32_t',
'int64': 'int64_t',
'uint8': 'uint8_t',
'uint16': 'uint16_t',
'uint32': 'uint32_t',
'uint64': 'uint64_t',
'float32': 'float',
'float64': 'double',
'bool': 'bool',
'char': 'char',
}
type_idl_map = {
'bool': 'boolean',
'byte': 'octet',
'char': 'char',
'int8': 'octet',
'uint8': 'octet',
'int16': 'short',
'uint16': 'unsigned short',
'int32': 'long',
'uint32': 'unsigned long',
'int64': 'long long',
'uint64': 'unsigned long long',
'float32': 'float',
'float64': 'double',
'string': 'string',
}
msgtype_size_map = {
'int8': 1,
'int16': 2,
'int32': 4,
'int64': 8,
'uint8': 1,
'uint16': 2,
'uint32': 4,
'uint64': 8,
'float32': 4,
'float64': 8,
'bool': 1,
'char': 1,
}
type_printf_map = {
'int8': '%d',
'int16': '%d',
'int32': '%" PRId32 "',
'int64': '%" PRId64 "',
'uint8': '%u',
'uint16': '%u',
'uint32': '%" PRIu32 "',
'uint64': '%" PRIu64 "',
'float32': '%.4f',
'float64': '%.6f',
'bool': '%u',
'char': '%c',
}
def bare_name(msg_type):
"""
Get bare_name from <dir>/<bare_name>[x] format
"""
bare = msg_type
if '/' in msg_type:
# removing prefix
bare = (msg_type.split('/'))[1]
# removing suffix
return bare.split('[')[0]
def sizeof_field_type(field):
"""
Get size of a field, used for sorting
"""
bare_name_str = bare_name(field.type)
if bare_name_str in msgtype_size_map:
return msgtype_size_map[bare_name_str]
return 0 # this is for non-builtin types: sort them at the end
def get_children_fields(base_type, search_path):
(package, name) = genmsg.names.package_resource_name(base_type)
tmp_msg_context = genmsg.msg_loader.MsgContext.create_default()
spec_temp = genmsg.msg_loader.load_msg_by_type(
tmp_msg_context, '%s/%s' % (package, name), search_path)
return spec_temp.parsed_fields()
def add_padding_bytes(fields, search_path):
"""
Add padding fields before the embedded types, at the end and calculate the
struct size
returns a tuple with the struct size and padding at the end
"""
struct_size = 0
align_to = 8 # this is always 8, because of the 64bit timestamp
i = 0
padding_idx = 0
while i < len(fields):
field = fields[i]
if not field.is_header:
a_pos = field.type.find('[')
array_size = 1
if field.is_array:
array_size = field.array_len
if field.is_builtin:
field.sizeof_field_type = sizeof_field_type(field)
else:
# embedded type: may need to add padding
num_padding_bytes = align_to - (struct_size % align_to)
if num_padding_bytes != align_to:
padding_field = genmsg.Field('_padding' + str(padding_idx),
'uint8[' + str(num_padding_bytes) + ']')
padding_idx += 1
padding_field.sizeof_field_type = 1
struct_size += num_padding_bytes
fields.insert(i, padding_field)
i += 1
children_fields = get_children_fields(
field.base_type, search_path)
field.sizeof_field_type, unused = add_padding_bytes(children_fields,
search_path)
struct_size += field.sizeof_field_type * array_size
i += 1
# add padding at the end (necessary for embedded types)
num_padding_bytes = align_to - (struct_size % align_to)
if num_padding_bytes == align_to:
num_padding_bytes = 0
else:
padding_field = genmsg.Field('_padding' + str(padding_idx),
'uint8[' + str(num_padding_bytes) + ']')
padding_idx += 1
padding_field.sizeof_field_type = 1
struct_size += num_padding_bytes
fields.append(padding_field)
return (struct_size, num_padding_bytes)
def convert_type(spec_type, use_short_type=False):
"""
Convert from msg type to C type
"""
bare_type = spec_type
if '/' in spec_type:
# removing prefix
bare_type = (spec_type.split('/'))[1]
msg_type, is_array, array_length = genmsg.msgs.parse_type(bare_type)
c_type = msg_type
if use_short_type and msg_type in type_map_short:
c_type = type_map_short[msg_type]
elif msg_type in type_map:
c_type = type_map[msg_type]
else:
c_type = re.sub(r'(?<!^)(?=[A-Z])', '_', c_type).lower() # PascalCase to snake_case
if is_array:
return c_type + "[" + str(array_length) + "]"
return c_type
def print_field_def(field):
"""
Print the C type from a field
"""
# check if there are any upper case letters in the field name
assert not any(a.isupper()
for a in field.name), "%r field contains uppercase letters" % field.name
type_name = field.type
# detect embedded types
sl_pos = type_name.find('/')
type_appendix = ''
type_prefix = ''
if (sl_pos >= 0):
type_name = type_name[sl_pos + 1:]
type_name = re.sub(r'(?<!^)(?=[A-Z])', '_', type_name).lower() # PascalCase to snake_case
type_prefix = 'struct '
type_appendix = '_s'
# detect arrays
a_pos = type_name.find('[')
array_size = ''
if (a_pos >= 0):
# field is array
array_size = type_name[a_pos:]
type_name = type_name[:a_pos]
if type_name in type_map:
# need to add _t: int8 --> int8_t
type_px4 = type_map[type_name]
else:
type_px4 = type_name
comment = ''
if field.name.startswith('_padding'):
comment = ' // required for logger'
print(('\t%s%s%s %s%s;%s' % (type_prefix, type_px4, type_appendix, field.name,
array_size, comment)))
+174
View File
@@ -0,0 +1,174 @@
@###############################################
@#
@# EmPy template
@#
@###############################################
@# generates CDR serialization & deserialization methods
@#
@# Context:
@# - file_name_in (String) Source file
@# - spec (msggen.MsgSpec) Parsed specification of the .msg file
@# - search_path (dict) search paths for genmsg
@# - topics (List of String) topic names
@###############################################
/****************************************************************************
*
* Copyright (C) 2013-2022 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
@{
import genmsg.msgs
import re
from px_generate_uorb_topic_helper import * # this is in Tools/
topic = name_snake_case
uorb_struct = '%s_s'%name_snake_case
# get fields, struct size and paddings
def add_fields(msg_fields, name_prefix='', offset=0):
fields = []
for field in msg_fields:
if not field.is_header:
field_size = sizeof_field_type(field)
type_name = field.type
# detect embedded types
sl_pos = type_name.find('/')
if (sl_pos >= 0):
package = type_name[:sl_pos]
type_name = type_name[sl_pos + 1:]
# detect arrays
a_pos = type_name.find('[')
array_size = 1
if (a_pos >= 0):
# field is array
array_size = int(type_name[a_pos+1:-1])
type_name = type_name[:a_pos]
if sl_pos >= 0: # nested type
children_fields = get_children_fields(field.base_type, search_path)
for i in range(array_size):
sub_name_prefix = name_prefix+field.name
if array_size > 1:
sub_name_prefix += '['+str(i)+']'
sub_fields, offset = add_fields(children_fields, sub_name_prefix+'.', offset)
fields.extend(sub_fields)
else:
assert field_size > 0
# note: the maximum alignment for XCDR is 8 and for XCDR2 it is 4
padding = (field_size - (offset % field_size)) & (field_size - 1)
fields.append((type_name, name_prefix+field.name, field_size * array_size, padding))
offset += array_size * field_size + padding
return fields, offset
fields, struct_size = add_fields(spec.parsed_fields())
}@
// auto-generated file
#pragma once
#include <ucdr/microcdr.h>
#include <string.h>
#include <uORB/topics/@(topic).h>
@##############################
@# Includes for dependencies
@##############################
@{
for field in spec.parsed_fields():
if (not field.is_builtin):
if not field.is_header:
(package, name) = genmsg.names.package_resource_name(field.base_type)
package = package or spec.package # convert '' to package
name_snake = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print('#include <uORB/ucdr/%s.h>'%(name_snake))
}@
static inline constexpr int ucdr_topic_size_@(topic)()
{
return @(struct_size);
}
bool ucdr_serialize_@(topic)(const @(uorb_struct)& topic, ucdrBuffer& buf, int64_t time_offset = 0)
{
@{
for field_type, field_name, field_size, padding in fields:
if padding > 0:
print('\tbuf.iterator += {:}; // padding'.format(padding))
print('\tbuf.offset += {:}; // padding'.format(padding))
print('\tstatic_assert(sizeof(topic.{0}) == {1}, "size mismatch");'.format(field_name, field_size))
if field_type == 'uint64' and field_name == 'timestamp':
print('\tconst uint64_t timestamp_adjusted = topic.timestamp + time_offset;')
print('\tmemcpy(buf.iterator, &timestamp_adjusted, sizeof(topic.{0}));'.format(field_name))
elif field_type == 'uint64' and field_name == 'timestamp_sample':
print('\tconst uint64_t timestamp_sample_adjusted = topic.timestamp_sample + time_offset;')
print('\tmemcpy(buf.iterator, &timestamp_sample_adjusted, sizeof(topic.{0}));'.format(field_name))
else:
print('\tmemcpy(buf.iterator, &topic.{0}, sizeof(topic.{0}));'.format(field_name))
print('\tbuf.iterator += sizeof(topic.{:});'.format(field_name))
print('\tbuf.offset += sizeof(topic.{:});'.format(field_name))
}@
return true;
}
bool ucdr_deserialize_@(topic)(ucdrBuffer& buf, @(uorb_struct)& topic, int64_t time_offset = 0)
{
@{
for field_type, field_name, field_size, padding in fields:
if padding > 0:
print('\tbuf.iterator += {:}; // padding'.format(padding))
print('\tbuf.offset += {:}; // padding'.format(padding))
print('\tstatic_assert(sizeof(topic.{0}) == {1}, "size mismatch");'.format(field_name, field_size))
print('\tmemcpy(&topic.{0}, buf.iterator, sizeof(topic.{0}));'.format(field_name))
if field_type == 'uint64' and (field_name == 'timestamp' or field_name == 'timestamp_sample'):
print('\ttopic.{0} -= time_offset;'.format(field_name))
print('\tbuf.iterator += sizeof(topic.{:});'.format(field_name))
print('\tbuf.offset += sizeof(topic.{:});'.format(field_name))
}@
return true;
}
+90
View File
@@ -0,0 +1,90 @@
@###############################################
@#
@# PX4 ROS compatible message source code
@# generation for C++
@#
@# EmPy template for generating <msg>.h files
@# Based on the original template for ROS
@#
@###############################################
@# Start of Template
@#
@# Context:
@# - file_name_in (String) Source file
@# - spec (msggen.MsgSpec) Parsed specification of the .msg file
@# - search_path (dict) search paths for genmsg
@# - topics (List of String) topic names
@###############################################
/****************************************************************************
*
* Copyright (C) 2013-2022 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/* Auto-generated by genmsg_cpp from file @file_name_in */
@{
import genmsg.msgs
from px_generate_uorb_topic_helper import * # this is in Tools/
uorb_struct = '%s_s'%name_snake_case
sorted_fields = sorted(spec.parsed_fields(), key=sizeof_field_type, reverse=True)
struct_size, padding_end_size = add_padding_bytes(sorted_fields, search_path)
topic_fields = ["%s %s" % (convert_type(field.type, True), field.name) for field in sorted_fields]
}@
#include <inttypes.h>
#include <px4_platform_common/log.h>
#include <px4_platform_common/defines.h>
#include <uORB/topics/@(name_snake_case).h>
#include <uORB/topics/uORBTopics.hpp>
#include <drivers/drv_hrt.h>
#include <lib/drivers/device/Device.hpp>
#include <lib/matrix/matrix/math.hpp>
#include <lib/mathlib/mathlib.h>
@# join all msg files in one line e.g: "float[3] position;float[3] velocity;bool armed"
@# This is used for the logger
constexpr char __orb_@(name_snake_case)_fields[] = "@( ";".join(topic_fields) );";
@[for topic in topics]@
ORB_DEFINE(@topic, struct @uorb_struct, @(struct_size-padding_end_size), __orb_@(name_snake_case)_fields, static_cast<uint8_t>(ORB_ID::@topic));
@[end for]
void print_message(const orb_metadata *meta, const @uorb_struct& message)
{
if (sizeof(message) != meta->o_size) {
printf("unexpected message size for %s: %zu != %i\n", meta->o_name, sizeof(message), meta->o_size);
return;
}
orb_print_message_internal(meta, &message, true);
}
+147
View File
@@ -0,0 +1,147 @@
@###############################################
@#
@# PX4 ROS compatible message source code
@# generation for C++
@#
@# EmPy template for generating <msg>.h files
@# Based on the original template for ROS
@#
@###############################################
@# Start of Template
@#
@# Context:
@# - file_name_in (String) Source file
@# - spec (msggen.MsgSpec) Parsed specification of the .msg file
@# - search_path (dict) search paths for genmsg
@# - topics (List of String) topic names
@###############################################
/****************************************************************************
*
* Copyright (C) 2013-2022 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/* Auto-generated by genmsg_cpp from file @file_name_in */
@{
import genmsg.msgs
import re
from px_generate_uorb_topic_helper import * # this is in Tools/
uorb_struct = '%s_s'%name_snake_case
uorb_struct_upper = name_snake_case.upper()
}@
#pragma once
@##############################
@# Generic Includes
@##############################
#include <uORB/uORB.h>
@##############################
@# Includes for dependencies
@##############################
@{
for field in spec.parsed_fields():
if (not field.is_builtin):
if (not field.is_header):
(package, name) = genmsg.names.package_resource_name(field.base_type)
package = package or spec.package # convert '' to package
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print('#include <uORB/topics/%s.h>'%(name))
}@
@# Constants c style
#ifndef __cplusplus
@[for constant in spec.constants]@
#define @(uorb_struct_upper)_@(constant.name) @(int(constant.val))
@[end for]
#endif
@##############################
@# Main struct of message
@##############################
@{
def print_parsed_fields():
# sort fields (using a stable sort)
sorted_fields = sorted(spec.parsed_fields(), key=sizeof_field_type, reverse=True)
struct_size, padding_end_size = add_padding_bytes(sorted_fields, search_path)
# loop over all fields and print the type and name
for field in sorted_fields:
if (not field.is_header):
print_field_def(field)
}@
#ifdef __cplusplus
@#class @(uorb_struct) {
struct __EXPORT @(uorb_struct) {
@#public:
#else
struct @(uorb_struct) {
#endif
@print_parsed_fields()
#ifdef __cplusplus
@# Constants again c++-ified
@{
for constant in spec.constants:
type_name = constant.type
if type_name in type_map:
# need to add _t: int8 --> int8_t
type_px4 = type_map[type_name]
else:
raise Exception("Type {0} not supported, add to to template file!".format(type_name))
print('\tstatic constexpr %s %s = %s;'%(type_px4, constant.name, int(constant.val)))
}
#endif
};
#ifdef __cplusplus
namespace px4 {
namespace msg {
using @(spec.short_name) = @(uorb_struct);
} // namespace msg
} // namespace px4
#endif
/* register this as object request broker structure */
@[for topic in topics]@
ORB_DECLARE(@topic);
@[end for]
#ifdef __cplusplus
void print_message(const orb_metadata *meta, const @uorb_struct& message);
#endif
@@ -0,0 +1,80 @@
@###############################################
@#
@# EmPy template for generating uORBTopics.cpp file
@# for logging purposes
@#
@###############################################
@# Start of Template
@#
@# Context:
@# - msgs (List) list of all msg files
@# - multi_topics (List) list of all multi-topic names
@###############################################
/****************************************************************************
*
* Copyright (C) 2013-2022 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <uORB/topics/uORBTopics.hpp>
#include <uORB/uORB.h>
@{
msg_names = list(set([mn.replace(".msg", "") for mn in msgs])) # set() filters duplicates
msg_names.sort()
msgs_count = len(msg_names)
topic_names = list(set(topics)) # set() filters duplicates
topic_names.sort()
topics_count = len(topics)
}@
@[for msg_name in msg_names]@
#include <uORB/topics/@(msg_name).h>
@[end for]
const constexpr struct orb_metadata *const uorb_topics_list[ORB_TOPICS_COUNT] = {
@[for idx, topic_name in enumerate(topic_names, 1)]@
ORB_ID(@(topic_name))@[if idx != topic_names], @[end if]
@[end for]
};
const struct orb_metadata *const *orb_get_topics()
{
return uorb_topics_list;
}
const struct orb_metadata *get_orb_meta(ORB_ID id)
{
if (id == ORB_ID::INVALID) {
return nullptr;
}
return uorb_topics_list[static_cast<uint8_t>(id)];
}
@@ -0,0 +1,72 @@
@###############################################
@#
@# EmPy template for generating uORBTopics.hpp file
@# for logging purposes
@#
@###############################################
@# Start of Template
@#
@# Context:
@# - topics (List) list of all topic names
@###############################################
/****************************************************************************
*
* Copyright (C) 2021-2022 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
@{
topics_count = len(topics)
topic_names_all = list(set(topics)) # set() filters duplicates
topic_names_all.sort()
}@
#pragma once
#include <stddef.h>
#include <uORB/uORB.h>
static constexpr size_t ORB_TOPICS_COUNT{@(topics_count)};
static constexpr size_t orb_topics_count() { return ORB_TOPICS_COUNT; }
/*
* Returns array of topics metadata
*/
extern const struct orb_metadata *const *orb_get_topics() __EXPORT;
enum class ORB_ID : uint8_t {
@[for idx, topic_name in enumerate(topic_names_all)]@
@(topic_name) = @(idx),
@[end for]
INVALID
};
const struct orb_metadata *get_orb_meta(ORB_ID id);