2018-09-30 13:25:02 -03:00
#!/usr/bin/env python
################################################################################
#
2019-11-25 07:15:52 -04:00
# Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
2018-09-30 13:25:02 -03:00
#
# 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 of the copyright holder 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 HOLDER 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 sys
import os
import argparse
2019-12-19 06:05:55 -04:00
import errno
2018-09-30 15:23:56 -03:00
import yaml
2019-06-01 10:27:21 -03:00
import re
2019-06-03 16:54:12 -03:00
import difflib
2018-09-30 13:25:02 -03:00
class Classifier ( ) :
"""
Class to classify RTPS msgs as senders , receivers or to be ignored
"""
2018-09-30 15:23:56 -03:00
def __init__ ( self , yaml_file , msg_folder ) :
2018-09-30 13:25:02 -03:00
self . msg_folder = msg_folder
2019-06-01 10:27:21 -03:00
self . all_msgs_list = self . set_all_msgs ( )
self . msg_id_map = self . parse_yaml_msg_id_file ( yaml_file )
2019-08-25 18:45:43 -03:00
self . alias_space_init_id = 150
2019-06-03 16:54:12 -03:00
# Checkers
2019-06-01 10:27:21 -03:00
self . check_if_listed ( yaml_file )
2019-06-03 16:54:12 -03:00
self . check_base_type ( )
2019-08-25 18:45:43 -03:00
self . check_id_space ( )
2019-06-01 10:27:21 -03:00
2019-06-02 12:12:50 -03:00
self . msgs_to_send , self . alias_msgs_to_send = self . set_msgs_to_send ( )
self . msgs_to_receive , self . alias_msgs_to_receive = self . set_msgs_to_receive ( )
self . msgs_to_ignore , self . alias_msgs_to_ignore = self . set_msgs_to_ignore ( )
2018-10-02 12:04:46 -03:00
self . msg_files_send = self . set_msg_files_send ( )
self . msg_files_receive = self . set_msg_files_receive ( )
self . msg_files_ignore = self . set_msg_files_ignore ( )
2018-09-30 13:25:02 -03:00
# setters (for class init)
2019-06-01 10:27:21 -03:00
def set_all_msgs ( self ) :
msg_list = [ ]
for filename in os . listdir ( self . msg_folder ) :
if ' .msg ' in filename :
msg_list . append ( re . sub ( " .msg " , " " , filename ) )
return msg_list
2018-09-30 13:25:02 -03:00
def set_msgs_to_send ( self ) :
2018-10-02 12:04:46 -03:00
send = { }
2019-06-02 12:12:50 -03:00
send_alias = [ ]
2018-10-06 11:58:26 -03:00
for dict in self . msg_id_map [ ' rtps ' ] :
if ' send ' in dict . keys ( ) :
2019-06-02 12:12:50 -03:00
if ' alias ' in dict . keys ( ) :
2019-06-03 16:54:12 -03:00
send_alias . append (
( { dict [ ' msg ' ] : dict [ ' id ' ] } , dict [ ' alias ' ] ) )
2019-06-02 12:12:50 -03:00
else :
send . update ( { dict [ ' msg ' ] : dict [ ' id ' ] } )
return send , send_alias
2018-09-30 13:25:02 -03:00
def set_msgs_to_receive ( self ) :
2018-10-02 12:04:46 -03:00
receive = { }
2019-06-02 12:12:50 -03:00
receive_alias = [ ]
2018-10-06 11:58:26 -03:00
for dict in self . msg_id_map [ ' rtps ' ] :
if ' receive ' in dict . keys ( ) :
2019-06-02 12:12:50 -03:00
if ' alias ' in dict . keys ( ) :
2019-06-03 16:54:12 -03:00
receive_alias . append (
( { dict [ ' msg ' ] : dict [ ' id ' ] } , dict [ ' alias ' ] ) )
2019-06-02 12:12:50 -03:00
else :
receive . update ( { dict [ ' msg ' ] : dict [ ' id ' ] } )
return receive , receive_alias
2018-09-30 13:25:02 -03:00
def set_msgs_to_ignore ( self ) :
2018-10-02 12:04:46 -03:00
ignore = { }
2019-06-02 12:12:50 -03:00
ignore_alias = [ ]
2018-10-06 11:58:26 -03:00
for dict in self . msg_id_map [ ' rtps ' ] :
2019-06-02 12:12:50 -03:00
if ( ( ' send ' not in dict . keys ( ) ) and ( ' receive ' not in dict . keys ( ) ) ) :
if ' alias ' in dict . keys ( ) :
2019-06-03 16:54:12 -03:00
ignore_alias . append (
( { dict [ ' msg ' ] : dict [ ' id ' ] } , dict [ ' alias ' ] ) )
2019-06-02 12:12:50 -03:00
else :
ignore . update ( { dict [ ' msg ' ] : dict [ ' id ' ] } )
return ignore , ignore_alias
2018-09-30 13:25:02 -03:00
def set_msg_files_send ( self ) :
2018-10-02 12:04:46 -03:00
return [ os . path . join ( self . msg_folder , msg + " .msg " )
2018-10-06 11:58:26 -03:00
for msg in self . msgs_to_send . keys ( ) ]
2018-09-30 13:25:02 -03:00
def set_msg_files_receive ( self ) :
2018-10-02 12:04:46 -03:00
return [ os . path . join ( self . msg_folder , msg + " .msg " )
2018-10-06 11:58:26 -03:00
for msg in self . msgs_to_receive . keys ( ) ]
2018-09-30 13:25:02 -03:00
def set_msg_files_ignore ( self ) :
2018-10-02 12:04:46 -03:00
return [ os . path . join ( self . msg_folder , msg + " .msg " )
2018-10-06 11:58:26 -03:00
for msg in self . msgs_to_ignore . keys ( ) ]
2018-09-30 13:25:02 -03:00
2019-06-01 10:27:21 -03:00
def check_if_listed ( self , yaml_file ) :
"""
Checks if all msgs are listed under the RTPS ID yaml file
"""
none_listed_msgs = [ ]
for msg in self . all_msgs_list :
result = not any (
2019-08-04 14:54:04 -03:00
dict [ ' msg ' ] == msg for dict in self . msg_id_map [ ' rtps ' ] )
2019-06-01 10:27:21 -03:00
if result :
none_listed_msgs . append ( msg )
if len ( none_listed_msgs ) > 0 :
if len ( none_listed_msgs ) == 1 :
error_msg = " The following message is not listen under "
elif len ( none_listed_msgs ) > 1 :
error_msg = " The following messages are not listen under "
raise AssertionError (
" \n %s %s : " % ( error_msg , yaml_file ) + " , " . join ( ' %s ' % msg for msg in none_listed_msgs ) +
2019-08-04 14:54:04 -03:00
" \n \n Please add them to the yaml file with the respective ID and, if applicable, mark them " +
2019-06-01 10:27:21 -03:00
" to be sent or received by the micro-RTPS bridge. \n "
" NOTE: If the message has multi-topics (#TOPICS), these should be added as well. \n " )
2019-06-03 16:54:12 -03:00
def check_base_type ( self ) :
"""
Check if alias message has correct base type
"""
2019-08-25 18:21:44 -03:00
registered_alias_msgs = list (
2019-06-03 16:54:12 -03:00
dict [ ' alias ' ] for dict in self . msg_id_map [ ' rtps ' ] if ' alias ' in dict . keys ( ) )
2019-08-25 18:21:44 -03:00
base_types = [ ]
for dict in self . msg_id_map [ ' rtps ' ] :
if ' alias ' not in dict . keys ( ) :
base_types . append ( dict [ ' msg ' ] )
incorrect_base_types = list (
set ( registered_alias_msgs ) - set ( base_types ) )
base_types_suggestion = { }
2019-06-03 16:54:12 -03:00
for incorrect in incorrect_base_types :
2019-08-25 18:21:44 -03:00
base_types_suggestion . update ( { incorrect : difflib . get_close_matches (
incorrect , base_types , n = 1 , cutoff = 0.6 ) } )
2019-06-03 16:54:12 -03:00
2019-08-25 18:21:44 -03:00
if len ( base_types_suggestion ) > 0 :
2019-06-03 16:54:12 -03:00
raise AssertionError (
2019-08-25 18:45:43 -03:00
( ' \n ' + ' \n ' . join ( ' \t - The multi-topic message base type \' {} \' does not exist. {} ' . format ( k , ( ' Did you mean \' ' + v [ 0 ] + ' \' ? ' if v else ' ' ) ) for k , v in base_types_suggestion . items ( ) ) ) )
def check_id_space ( self ) :
"""
Check if msg ID is in the correct ID space
"""
incorrect_base_ids = { }
incorrect_alias_ids = { }
for dict in self . msg_id_map [ ' rtps ' ] :
if ' alias ' not in dict . keys ( ) and dict [ ' id ' ] > = self . alias_space_init_id :
incorrect_base_ids . update ( { dict [ ' msg ' ] : dict [ ' id ' ] } )
elif ' alias ' in dict . keys ( ) and dict [ ' id ' ] < self . alias_space_init_id :
incorrect_alias_ids . update ( { dict [ ' msg ' ] : dict [ ' id ' ] } )
if len ( incorrect_base_ids ) > 0 :
raise AssertionError (
( ' \n ' + ' \n ' . join ( ' \t - The message \' {} with ID \' {} \' is in the wrong ID space. Please use any of the available IDs from 0 to 149 ' . format ( k , v ) for k , v in incorrect_base_ids . items ( ) ) ) )
if len ( incorrect_alias_ids ) > 0 :
raise AssertionError (
( ' \n ' + ' \n ' . join ( ' \t - The alias message \' {} \' with ID \' {} \' is in the wrong ID space. Please use any of the available IDs from 149 to 255 ' . format ( k , v ) for k , v in incorrect_alias_ids . items ( ) ) ) )
2019-06-03 16:54:12 -03:00
2018-09-30 15:23:56 -03:00
@staticmethod
def parse_yaml_msg_id_file ( yaml_file ) :
"""
Parses a yaml file into a dict
"""
try :
with open ( yaml_file , ' r ' ) as f :
2019-07-11 03:18:12 -03:00
return yaml . safe_load ( f )
2018-09-30 15:23:56 -03:00
except OSError as e :
if e . errno == errno . ENOENT :
raise IOError ( errno . ENOENT , os . strerror (
errno . ENOENT ) , yaml_file )
else :
raise
2018-09-30 13:25:02 -03:00
if __name__ == " __main__ " :
parser = argparse . ArgumentParser ( )
parser . add_argument ( " -s " , " --send " , dest = ' send ' ,
2019-06-02 12:12:50 -03:00
action = " store_true " , help = " Get topics to be sent " )
parser . add_argument ( " -a " , " --alias " , dest = ' alias ' ,
action = " store_true " , help = " Get alias topics " )
2018-09-30 13:25:02 -03:00
parser . add_argument ( " -r " , " --receive " , dest = ' receive ' ,
action = " store_true " , help = " Get topics to be received " )
parser . add_argument ( " -i " , " --ignore " , dest = ' ignore ' ,
action = " store_true " , help = " Get topics to be ignored " )
parser . add_argument ( " -p " , " --path " , dest = ' path ' ,
action = " store_true " , help = " Get msgs and its paths " )
parser . add_argument ( " -m " , " --topic-msg-dir " , dest = ' msgdir ' , type = str ,
help = " Topics message dir, by default msg/ " , default = " msg " )
parser . add_argument ( " -y " , " --rtps-ids-file " , dest = ' yaml_file ' , type = str ,
2019-01-20 18:23:41 -04:00
help = " RTPS msg IDs definition file absolute path, by default use relative path to msg, tools/uorb_rtps_message_ids.yaml " ,
default = ' tools/uorb_rtps_message_ids.yaml ' )
2018-09-30 13:25:02 -03:00
# Parse arguments
args = parser . parse_args ( )
2019-01-27 09:01:22 -04:00
msg_dir = args . msgdir
2018-10-13 17:30:58 -03:00
if args . msgdir == ' msg ' :
2019-01-27 09:01:22 -04:00
msg_dir = os . path . dirname ( os . path . dirname ( os . path . abspath ( __file__ ) ) )
2019-01-20 18:23:41 -04:00
else :
2019-01-27 09:01:22 -04:00
msg_dir = os . path . abspath ( args . msgdir )
2019-06-01 10:27:21 -03:00
classifier = ( Classifier ( os . path . abspath ( args . yaml_file ) , msg_dir ) if os . path . isabs ( args . yaml_file )
else Classifier ( os . path . join ( msg_dir , args . yaml_file ) , msg_dir ) )
2018-09-30 13:25:02 -03:00
if args . send :
if args . path :
print ( ' send files: ' + ' , ' . join ( str ( msg_file )
for msg_file in classifier . msgs_files_send ) + ' \n ' )
else :
2019-06-02 12:12:50 -03:00
if args . alias :
2019-08-04 14:54:04 -03:00
if sys . version_info [ 0 ] < 3 :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_send . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( msg [ 0 ] . keys ( ) [ 0 ] )
for msg in classifier . alias_msgs_to_send ) if len ( classifier . alias_msgs_to_send ) > 0 else ' ' ) + ' \n ' )
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_send . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( list ( msg [ 0 ] . keys ( ) ) [ 0 ] )
for msg in classifier . alias_msgs_to_send ) if len ( classifier . alias_msgs_to_send ) > 0 else ' ' ) + ' \n ' )
2019-06-02 12:12:50 -03:00
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_send . keys ( ) ) )
2018-09-30 13:25:02 -03:00
if args . receive :
if args . path :
print ( ' receive files: ' + ' , ' . join ( str ( msg_file )
for msg_file in classifier . msgs_files_receive ) + ' \n ' )
else :
2019-06-02 12:12:50 -03:00
if args . alias :
2019-08-04 14:54:04 -03:00
if sys . version_info [ 0 ] < 3 :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_receive . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( msg [ 0 ] . keys ( ) [ 0 ] )
for msg in classifier . alias_msgs_to_receive ) if len ( classifier . alias_msgs_to_receive ) > 0 else ' ' ) + ' \n ' )
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_receive . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( list ( msg [ 0 ] . keys ( ) ) [ 0 ] )
for msg in classifier . alias_msgs_to_receive ) if len ( classifier . alias_msgs_to_receive ) > 0 else ' ' ) + ' \n ' )
2019-06-02 12:12:50 -03:00
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_receive . keys ( ) ) )
2018-09-30 13:25:02 -03:00
if args . ignore :
if args . path :
print ( ' ignore files: ' + ' , ' . join ( str ( msg_file )
for msg_file in classifier . msgs_files_ignore ) + ' \n ' )
else :
2019-06-02 12:12:50 -03:00
if args . alias :
2019-08-04 14:54:04 -03:00
if sys . version_info [ 0 ] < 3 :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_ignore . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( msg [ 0 ] . keys ( ) [ 0 ] )
for msg in classifier . alias_msgs_to_ignore ) if len ( classifier . alias_msgs_to_ignore ) > 0 else ' ' ) + ' \n ' )
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_ignore . keys ( ) ) + ( ' alias ' + ' , ' . join ( str ( list ( msg [ 0 ] . keys ( ) ) [ 0 ] )
for msg in classifier . alias_msgs_to_ignore ) if len ( classifier . alias_msgs_to_ignore ) > 0 else ' ' ) + ' \n ' )
2019-06-02 12:12:50 -03:00
else :
print ( ' , ' . join ( str ( msg )
for msg in classifier . msgs_to_ignore . keys ( ) ) )