|
| 1 | +#!/usr/bin/env python3 |
| 2 | +############################################################################# |
| 3 | +# |
| 4 | +# Copyright (C) 2013-2022 PX4 Pro Development Team. All rights reserved. |
| 5 | +# |
| 6 | +# Redistribution and use in source and binary forms, with or without |
| 7 | +# modification, are permitted provided that the following conditions |
| 8 | +# are met: |
| 9 | +# |
| 10 | +# 1. Redistributions of source code must retain the above copyright |
| 11 | +# notice, this list of conditions and the following disclaimer. |
| 12 | +# 2. Redistributions in binary form must reproduce the above copyright |
| 13 | +# notice, this list of conditions and the following disclaimer in |
| 14 | +# the documentation and/or other materials provided with the |
| 15 | +# distribution. |
| 16 | +# 3. Neither the name PX4 nor the names of its contributors may be |
| 17 | +# used to endorse or promote products derived from this software |
| 18 | +# without specific prior written permission. |
| 19 | +# |
| 20 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 23 | +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 24 | +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 25 | +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 26 | +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| 27 | +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| 28 | +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 29 | +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| 30 | +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 31 | +# POSSIBILITY OF SUCH DAMAGE. |
| 32 | +# |
| 33 | +############################################################################# |
| 34 | + |
| 35 | +""" |
| 36 | +px_generate_zenoh_topic_files.py |
| 37 | +Generates c/cpp header/source files for use with zenoh |
| 38 | +message files |
| 39 | +""" |
| 40 | + |
| 41 | +import os |
| 42 | +import argparse |
| 43 | +import re |
| 44 | +import sys |
| 45 | + |
| 46 | +try: |
| 47 | + import em |
| 48 | +except ImportError as e: |
| 49 | + print("Failed to import em: " + str(e)) |
| 50 | + print("") |
| 51 | + print("You may need to install it using:") |
| 52 | + print(" pip3 install --user empy") |
| 53 | + print("") |
| 54 | + sys.exit(1) |
| 55 | + |
| 56 | +try: |
| 57 | + import genmsg.template_tools |
| 58 | +except ImportError as e: |
| 59 | + print("Failed to import genmsg: " + str(e)) |
| 60 | + print("") |
| 61 | + print("You may need to install it using:") |
| 62 | + print(" pip3 install --user pyros-genmsg") |
| 63 | + print("") |
| 64 | + sys.exit(1) |
| 65 | + |
| 66 | + |
| 67 | +__author__ = "Sergey Belash, Thomas Gubler, Beat Kueng" |
| 68 | +__copyright__ = "Copyright (C) 2013-2022 PX4 Development Team." |
| 69 | +__license__ = "BSD" |
| 70 | +__email__ = "thomasgubler@gmail.com" |
| 71 | + |
| 72 | +ZENOH_TEMPLATE_FILE = ['Kconfig.topics.em', 'uorb_pubsub_factory.hpp.em'] |
| 73 | +TOPICS_TOKEN = '# TOPICS ' |
| 74 | + |
| 75 | + |
| 76 | +def get_topics(filename): |
| 77 | + """ |
| 78 | + Get TOPICS names from a "# TOPICS" line |
| 79 | + """ |
| 80 | + ofile = open(filename, 'r') |
| 81 | + text = ofile.read() |
| 82 | + result = [] |
| 83 | + for each_line in text.split('\n'): |
| 84 | + if each_line.startswith(TOPICS_TOKEN): |
| 85 | + topic_names_str = each_line.strip() |
| 86 | + topic_names_str = topic_names_str.replace(TOPICS_TOKEN, "") |
| 87 | + topic_names_list = topic_names_str.split(" ") |
| 88 | + for topic in topic_names_list: |
| 89 | + # topic name PascalCase (file name) to snake_case (topic name) |
| 90 | + topic_name = re.sub(r'(?<!^)(?=[A-Z])', '_', topic).lower() |
| 91 | + result.append(topic_name) |
| 92 | + ofile.close() |
| 93 | + |
| 94 | + if len(result) == 0: |
| 95 | + # topic name PascalCase (file name) to snake_case (topic name) |
| 96 | + file_base_name = os.path.basename(filename).replace(".msg", "") |
| 97 | + topic_name = re.sub(r'(?<!^)(?=[A-Z])', '_', file_base_name).lower() |
| 98 | + result.append(topic_name) |
| 99 | + |
| 100 | + return result |
| 101 | + |
| 102 | +def generate_by_template(output_file, template_file, em_globals): |
| 103 | + """ |
| 104 | + Invokes empy intepreter to geneate output_file by the |
| 105 | + given template_file and predefined em_globals dict |
| 106 | + """ |
| 107 | + # check if folder exists: |
| 108 | + folder_name = os.path.dirname(output_file) |
| 109 | + if not os.path.exists(folder_name): |
| 110 | + os.makedirs(folder_name) |
| 111 | + |
| 112 | + ofile = open(output_file, 'w') |
| 113 | + # todo, reuse interpreter |
| 114 | + interpreter = em.Interpreter(output=ofile, globals=em_globals, options={ |
| 115 | + em.RAW_OPT: True, em.BUFFERED_OPT: True}) |
| 116 | + try: |
| 117 | + interpreter.file(open(template_file)) |
| 118 | + except OSError as e: |
| 119 | + ofile.close() |
| 120 | + os.remove(output_file) |
| 121 | + raise |
| 122 | + interpreter.shutdown() |
| 123 | + ofile.close() |
| 124 | + return True |
| 125 | + |
| 126 | + |
| 127 | +def generate_topics_list_file_from_files(files, outputdir, template_filename, templatedir): |
| 128 | + # generate cpp file with topics list |
| 129 | + filenames = [] |
| 130 | + for filename in [os.path.basename(p) for p in files if os.path.basename(p).endswith(".msg")]: |
| 131 | + filenames.append(re.sub(r'(?<!^)(?=[A-Z])', '_', filename).lower()) |
| 132 | + |
| 133 | + datatypes = [] |
| 134 | + for filename in [os.path.basename(p) for p in files if os.path.basename(p).endswith(".msg")]: |
| 135 | + datatypes.append(re.sub(r'(?<!^)(?=[A-Z])', '_', filename).lower().replace(".msg","")) |
| 136 | + |
| 137 | + full_base_names = [] |
| 138 | + for filename in [os.path.basename(p) for p in files if os.path.basename(p).endswith(".msg")]: |
| 139 | + full_base_names.append(filename.replace(".msg","")) |
| 140 | + |
| 141 | + topics = [] |
| 142 | + for msg_filename in files: |
| 143 | + topics.extend(get_topics(msg_filename)) |
| 144 | + |
| 145 | + tl_globals = {"msgs": filenames, "topics": topics, "datatypes": datatypes, "full_base_names": full_base_names} |
| 146 | + tl_template_file = os.path.join(templatedir, template_filename) |
| 147 | + tl_out_file = os.path.join(outputdir, template_filename.replace(".em", "")) |
| 148 | + |
| 149 | + generate_by_template(tl_out_file, tl_template_file, tl_globals) |
| 150 | + |
| 151 | +if __name__ == "__main__": |
| 152 | + parser = argparse.ArgumentParser(description='Convert msg files to uorb headers/sources') |
| 153 | + parser.add_argument('--zenoh-config', help='Generate Zenoh Kconfig file', action='store_true') |
| 154 | + parser.add_argument('--zenoh-pub-sub', help='Generate Zenoh Pubsub factory', action='store_true') |
| 155 | + parser.add_argument('-f', dest='file', |
| 156 | + help="files to convert (use only without -d)", |
| 157 | + nargs="+") |
| 158 | + parser.add_argument('-e', dest='templatedir', |
| 159 | + help='directory with template files',) |
| 160 | + parser.add_argument('-o', dest='outputdir', |
| 161 | + help='output directory for header files') |
| 162 | + parser.add_argument('-p', dest='prefix', default='', |
| 163 | + help='string added as prefix to the output file ' |
| 164 | + ' name when converting directories') |
| 165 | + args = parser.parse_args() |
| 166 | + |
| 167 | + if args.zenoh_config: |
| 168 | + generate_topics_list_file_from_files(args.file, args.outputdir, ZENOH_TEMPLATE_FILE[0], args.templatedir) |
| 169 | + exit(0) |
| 170 | + elif args.zenoh_pub_sub: |
| 171 | + generate_topics_list_file_from_files(args.file, args.outputdir, ZENOH_TEMPLATE_FILE[1], args.templatedir) |
| 172 | + exit(0) |
| 173 | + else: |
| 174 | + print('Error: either --headers or --sources must be specified') |
| 175 | + exit(-1) |
0 commit comments