Esempio n. 1
0
    def setUsesTransformationFrame(self):

        # Controllo che il system in cui è incluso il process che include il thread abbia
        # un subcomponent di tipo tf
        if not tfs.hasTransformationFrameEnabledInSystem(self.system_root):
            self.associated_class.setUsesTransformationFrame(False)
            return False

        # Controllo che ho una connessione che parte dal mio thread ed esce verso il
        # process di tipo transformation frame
        tf_source_port_name = "tf"
        tf_connection_port_info = tfs.getConnectionPortInfoBySource(self.process, self.type, tf_source_port_name)

        # Il thread NON usa sicuramente i transformation frame
        if tf_connection_port_info is None:
            self.associated_class.setUsesTransformationFrame(False)
            return False

        (parent_name, parent_port) = tfs.getDestFromPortInfo(tf_connection_port_info)

        if not tfs.isConnectedToSystemTransformationFrame(self.system_root, parent_name, parent_port):
            self.associated_class.setUsesTransformationFrame(False)
            return False

        self.associated_class.setUsesTransformationFrame(True)
        return True
Esempio n. 2
0
    def __init__(self, process):
        self.process = process
        self.name = tfs.getName(process)
        self.type = tfs.getType(process)
        self.namespace = tfs.getNamespace(process)

        self.remap = []
        self.topic_ports = {}
Esempio n. 3
0
    def populateData(self):
        self.main_thread = self.associated_class.getMainThread()

        if self.main_thread is None:
            return False, "Unable to get the Main Thread"

        thread_function = tfs.getSubprogram(self.thread)
        if thread_function is None:
            return False, "Unable to find the right Subprogram"

        ############################
        ### TRANSFORMATION FRAME ###
        ############################

        # Controllo l'uso del Transformation Frame
        self.thread_uses_tf = self.setUsesTransformationFrame()

        ##################
        ### SUBSCRIBER ###
        ##################
        (status, desc) = self.populateSubscriberData()
        if not status:
            return status, desc

        #################
        ### PUBLISHER ###
        #################
        (status, desc) = self.populatePublisherData()
        if not status:
            return status, desc

        ###################
        ### SOURCE TEXT ###
        ###################

        self.source_text_function = self.createSourceTextFileFromSourceText(
            tfs.getSourceText(thread_function),
            tfs.getSourceName(thread_function))
        # Aggiungo la chiamata alla funzione custome
        if self.source_text_function:
            self.source_text_function.setFunctionType(self.output_type)
            self.source_text_function.addFunctionParameter(self.sub_input_var)
            self.source_text_function.setTF(self.thread_uses_tf)

            code = "{}.publish({});".format(
                self.var_publisher_pub.name,
                self.source_text_function.generateInlineCode())
            self.sub_callback.addMiddleCode(code)
        else:
            return False, "Unable to find Source_Text or Source_Name"

        return True, ""
Esempio n. 4
0
    def __init__(self, _system_root, _process, _thread, _associated_class):
        # AADLProcess a cui un AADLThread fa riferimento
        self.associated_class = _associated_class

        # Processo e thread relativi
        self.system_root = _system_root
        self.process = _process
        self.thread = _thread

        # Tipo thread
        self.type = tfs.getType(self.thread)

        # Nome del thread
        self.name = tfs.getName(self.thread)

        # TF
        self.thread_uses_tf = False
Esempio n. 5
0
    def getStateJSON(self):
        parameters = []
        variables = []

        # get the name of the JSON file
        json_file = tfs.getSourceText(self.process)
        json_schema = tfs.getInternalStateSourceText(self.process)

        if not json_file or not json_schema:
            log.warning("No Params and Vars file specified for {}".format(self.associated_class.node_name))
            return parameters, variables

        # absolute location of the JSON file
        # TODO - assumption: AADL and XML file locations are the same
        json_file = os.path.join(global_filepath.aadl_model_dir, json_file)
        json_schema = os.path.join(global_filepath.aadl_model_dir, json_schema)
        json_base_schema = sys.path[0]+"/internal_state_base.schema.json"

        try:
            loaded_json_file = json.load(open(json_file))
            loaded_json_schema = json.load(open(json_schema))
            loaded_json_base_schema = json.load(open(json_base_schema))
        except json.JSONDecodeError:
            print("invalid json file")
            return parameters, variables

        try:
            jsonschema.validate(loaded_json_file, loaded_json_base_schema)
            jsonschema.validate(loaded_json_file, loaded_json_schema)
        except jsonschema.exceptions.ValidationError:
            print("validation failed")
            return parameters, variables

        if self.JSON_PARAMS in loaded_json_schema[self.JSON_STATE]["properties"]:
            list_of_params = loaded_json_schema[self.JSON_STATE]["properties"][self.JSON_PARAMS]["properties"]
            values_of_params = loaded_json_file[self.JSON_PARAMS]
            for key, value in list_of_params.items():
                parameters.append(self.getVariableFromJSON(key, value, values_of_params.get(key)))

        if self.JSON_VARS in loaded_json_schema[self.JSON_STATE]["properties"]:
            list_of_vars = loaded_json_schema[self.JSON_STATE]["properties"][self.JSON_VARS]["properties"]
            values_of_vars = loaded_json_file[self.JSON_VARS]
            for key, value in list_of_vars.items():
                variables.append(self.getVariableFromJSON(key, value, values_of_vars.get(key)))

        return parameters, variables
def startGeneration():
    XMLTags.initialize()

    # Parameters

    # Input
    ocarina_ros_path = global_filepath.xml_folder_path
    xml_filename = global_filepath.xml_filename

    # Setup

    # Salvo il momento della generazione automatica, in modo da poterlo segnare nel file
    today = datetime.datetime.now()
    generated_on = today.strftime("%d/%m/%Y %H:%M:%S")
    print("Avvio generazione: {}".format(generated_on))

    # Read XML

    # Leggo il file XML generato dal backend ever_xml
    tree = etree.parse(os.path.join(ocarina_ros_path, xml_filename))

    # Ottengo la root del system preso in considerazione
    system_root = tree.getroot()

    # Siccome itererò su tutti i vari system disponbili, inzio ad aggiungere
    # la mia system root, dopo mano a mano aggiungerò anche tutti gli altri system su
    # cui fare code-generation
    systems = [{'system': system_root, 'parent': None}]

    while len(systems) > 0:
        s = systems.pop(0)

        generateSystemCode(s['system'], s['parent'])

        # Mi cerco eventuali system dentro ad altri system. Questo serve nel caso in cui un
        # system sia usato come subcomponents di un altro system. La cosa è ricorsiva, poiché
        # di volta in volta la system_root diventa il system considerato.
        # La prima visita si fa comunque alla system root, dopo si passa a visitare ricorsivamente
        # tutti i vari system
        sub_systems = s['system'].findall("./" +
                                          XMLTags.tags['TAG_SUBCOMPONENTS'] +
                                          "/" +
                                          XMLTags.tags['TAG_SUBCOMPONENT'] +
                                          "/" + XMLTags.tags['TAG_SYSTEM'] +
                                          "/" + "[" +
                                          XMLTags.tags['TAG_CATEGORY'] +
                                          "='system']")

        # Io so chi è il genitore dei nodi, mi basta chiedere il system con quel certo
        # namespace al systems manager
        system_parent = sm.getSystemForNamespace(tfs.getNamespace(s['system']))

        for sub_sys in sub_systems:
            systems.append({'system': sub_sys, 'parent': system_parent})

    sm.generateAllSystems()
Esempio n. 7
0
    def getDefaultTopicName(self, thread_port_name, input=False, output=False):
        if not input and not output:
            return False, "No direction specified"

        thread_name = tfs.getName(self.thread)

        # Ottengo tutte le connesioni di un processo che mappano la porta specificata in process_port_name
        # del thread associato a questo processo con una porta qualunque del thread.
        connections = tfs.getAllConnectionsPerPort(self.process, thread_name, thread_port_name,
                                                   input=input,
                                                   output=output)

        names = []

        # Per ognuna delle connesioni trovate sopra bisogna cercare la porta verso cui (o da cui) è presente
        # la connessione e poi cercare la proprietà del topic name su di essa
        for c in connections:

            process_port_name = None
            # Ottengo il nome della porta
            if input:
                port_info = tfs.getPortInfoByDestPortInfo(c, thread_name, thread_port_name)
                (process_name, process_port_name) = tfs.getSourceFromPortInfo(port_info)
            elif output:
                port_info = tfs.getPortInfoBySourcePortInfo(c, thread_name, thread_port_name)
                (process_name, process_port_name) = tfs.getDestFromPortInfo(port_info)

            # La porta è una feature, quindi si usa getFeatureByName
            process_port = tfs.getFeatureByName(self.process, process_port_name)

            (topic_namespace, topic_name) = tfs.getDefaultTopicName(process_port)

            if topic_namespace is None or topic_name is None:
                return False, "Unable to get topic name"

            names.append(topic_name)

        # Rimuovo i duplicati
        names = list(set(names))

        if len(names) < 1:
            return False, "No topic name defined"

        if len(names) > 1:
            return False, "Multiple topic names defined"

        self.topic = names[0]

        return True, ""
Esempio n. 8
0
    def __init__(self, system_root, namespace=None):

        # Caso di system veri e propri che contengono process
        if system_root is not None:
            self.system_root = system_root
            self.namespace = tfs.getNamespace(system_root)
            # Log dell'inizio della generazione del system
            log.info("System {}".format(tfs.getType(system_root)))

        # Caso di system che sono composti da data e basta e quindi
        # non hanno una vera e propria system root
        else:
            self.system_root = None
            self.namespace = namespace
            log.info("Data system {}".format(self.namespace))

        # Creo i file CMakeLists e PackageXML
        self.cmake_list = CMakeLists(self)
        self.package_xml = PackageXML(self)

        # Variabile che conterrà il launch file
        self.launch_file = None

        # Resetto la struttura di cartelle (eliminando anche tutti i file) solamente alla prima generazione
        # del namespace, in tutte le altre i file non vengono eliminati
        self.system_folder = folderTree.createSystemFolderTree(self.namespace,
                                                               delete=(not sm.isSystemAlreadyReset(self.namespace)))
        sm.addResetSystem(self.namespace)

        # Contiene tutti i nodi da generare
        self.nodes = []

        # Contiene tutti i messaggi da generare
        self.messages = []

        # Contiene tutti i servizi da generare
        self.services = []
Esempio n. 9
0
    def addPortForTopicFromPortName(self, port_name, connection):
        try:
            port = self.process.find("./" + XMLTags.tags['TAG_FEATURES'] +
                                     "/" + XMLTags.tags['TAG_FEATURE'] + "/" +
                                     "[" + XMLTags.tags['TAG_NAME'] + "='" +
                                     port_name + "']")
        except Exception:
            return False

        (topic_properties_namespace,
         default_topic_name) = tfs.getDefaultTopicName(port)
        (topic_properties_namespace,
         new_topic_name) = tfs.getTopicName(connection)

        if default_topic_name is None or new_topic_name is None:
            log.warning("No topic remap for port {} of process {}".format(
                port_name, self.name))
            return True

        # Se ho già controllato quella porta vado oltre
        if self.hasPortForTopic(port_name):
            if self.topic_ports[port_name] == new_topic_name:
                return True
            else:
                log.error(
                    "Multiple topics defined for port {} of process {}".format(
                        port_name, self.name))
                return False

        r = Remap(default_topic_name, new_topic_name)

        self.topic_ports[port_name] = new_topic_name

        self.addRemap(r)

        return True
Esempio n. 10
0
    def populateData(self):
        # Ottengo tutti i dati relativi al main thread
        (prepare, tearDown, errorHandler) = tfs.getMainThreadFunctions(self.thread)

        self.prepare = Prepare(self.associated_class)
        self.prepare.source_text_function = self.createSourceTextFileFromSourceText(tfs.getSourceText(prepare),
                                                                                    "custom_prepare")

        self.tearDown = TearDown(self.associated_class)
        self.tearDown.source_text_function = self.createSourceTextFileFromSourceText(tfs.getSourceText(tearDown),
                                                                                     "custom_teardown")

        # Aggiungo la chiamata alla funzione custome
        if self.tearDown.source_text_function:
            code = "{};".format(self.tearDown.source_text_function.generateInlineCode())
            self.tearDown.addMiddleCode(code)

        self.errorHandling = ErrorHandling(self.associated_class)
        self.errorHandling.source_text_function = self.createSourceTextFileFromSourceText(
            tfs.getSourceText(errorHandler),
            "custom_errorHandling")

        # Aggiungo la chiamata alla funzione custome
        if self.errorHandling.source_text_function:
            code = "{};".format(self.errorHandling.source_text_function.generateInlineCode())
            self.errorHandling.addBottomCode(code)

        self.associated_class.addPrivateMethod(self.prepare)
        self.associated_class.addPrivateMethod(self.tearDown)
        self.associated_class.addPrivateMethod(self.errorHandling)

        # Ottengo lo stato (parameters, variables) in ASN.1 del nodo
        # (parameters, variables) = self.getStateASN()
        (parameters, variables) = self.getStateJSON()

        # Se ho almeno parametri o variabili, allora genero
        # anche la node configuration, altrimenti no
        if len(parameters) > 0 or len(variables) > 0:
            type_internal_state = Type()
            type_internal_state.setTypeName("InternalState")

            internal_state_is = Variable(self.associated_class)
            internal_state_is.setName("is")
            internal_state_is.setType(type_internal_state)
            self.associated_class.addInternalVariable(internal_state_is)

            node_conf = NodeConfiguration(self.associated_class)
            self.associated_class.setNodeConfiguration(node_conf)

            if len(variables) > 0:
                vars_struct = VariablesStruct(self.associated_class)

                for v in variables:
                    vars_struct.addVariable(v)

                self.associated_class.node_configuration.addStruct(vars_struct)
                self.associated_class.node_configuration.has_variables = True

            # Se ho dei parametri, allora genero la struct
            if len(parameters) > 0:
                params_struct = ParametersStruct(self.associated_class)
                self.prepare.addTopCode("Parameters p;")

                for p in parameters:
                    params_struct.addVariable(p)
                    self.createHandlerForParameter(p)

                self.prepare.addMiddleCode("is.initialize(&p);")
                self.associated_class.node_configuration.addStruct(params_struct)
                self.associated_class.node_configuration.has_parameters = True
            else:
                self.prepare.addMiddleCode("is.initialize();")

        # Aggiungo la chiamata alla funzione custome
        if self.prepare.source_text_function:
            self.prepare.source_text_function.setFunctionType(Bool(self.associated_class))
            code = "return {};".format(self.prepare.source_text_function.generateInlineCode())
            self.prepare.addBottomCode(code)
        else:
            # Return alla fine del metodo main
            self.prepare.addBottomCode("return true;")

        return True, ""
Esempio n. 11
0
    def populateData(self):
        main_thread = self.associated_class.getMainThread()

        if main_thread == None:
            return (False, "Unable to get the Main Thread")

        ###################
        ### Output Port ###
        ###################

        # Essendo bidirezionale posso trovare la connessione sia come source che come dest
        conn_by_source = True
        process_output_port = tfs.getConnectionPortInfoBySource(
            self.process, self.type, self.output_port_name)
        if process_output_port == None:
            conn_by_source = False
            process_output_port = tfs.getConnectionPortInfoByDest(
                self.process, self.type, self.output_port_name)

        if process_output_port == None:
            return (
                False,
                "Unable to find the right binding between process requires subprogram access port and "
                "thread input port")

        if conn_by_source:
            (dest_parent_name,
             dest_name) = tfs.getDestFromPortInfo(process_output_port)
        else:
            (dest_parent_name,
             dest_name) = tfs.getSourceFromPortInfo(process_output_port)

        if dest_parent_name == None or dest_name == None:
            return (
                False,
                "Unable to find the process requires subprogram access port name"
            )

        self.process_port = tfs.getFeatureByName(self.process, name=dest_name)

        if self.process_port == None:
            return (
                False,
                "Unable to find the process requires subprogram access port feature"
            )

        # Dopo aver trovato la porta del process, controllo il nome di default del
        # services associato
        (topic_namespace, self.default_service_name) = tfs.getDefaultTopicName(
            self.process_port)

        if self.default_service_name == None:
            self.default_service_name = "service_name_default"
            log.warning(
                "Default Service Name not found, set as {} as default.".format(
                    self.default_service_name))

        ##################################
        ### ASN.1 Request and Response ###
        ##################################

        (aadl_namespace,
         aadl_type) = tfs.getPortDatatypeByPort(self.process_port)
        if aadl_namespace is None or aadl_type is None:
            return False, "Unable to identify process port type"

        # Controllo se c'è un file ASN.1 associato alla porta. Se c'è allora il tipo di servizio
        # è custom e lo dovrò generare, mentre se non c'è allora è un servizio standard ROS
        port_data_info = tfs.getPortDataInfo(self.process_port)
        if port_data_info is None:
            return False, "Unable to get the port data info for process port"

        self.asn_description = tfs.getSourceText(port_data_info)

        if self.asn_description is None:
            self.service = Service(aadl_namespace, aadl_type)
        else:
            # Creo il servizio custom e lo associo al nodo che lo ha generato
            self.service = sfs.getServiceFromJSON(self.asn_description,
                                                  self.associated_class)
        # if self.service == None:
        #     return (False, "Error in ASN.1 parsing")

        # self.associated_class.addService( self.service )

        # Genero ed aggiungo la libreria del services al nodo
        service_library = Library(self.service.namespace)
        service_library.setPath("{}/{}.h".format(self.service.namespace,
                                                 self.service.name))
        self.associated_class.addLibrary(service_library)

        ##########################
        ### SERVICE CLIENT VAR ###
        ##########################

        var_serviceclient = Variable(self.associated_class)
        var_serviceclient.setName("service_client_{}".format(self.name))
        var_serviceclient.setType(ROS_ServiceClient(self.associated_class))
        self.associated_class.addInternalVariable(var_serviceclient)

        main_thread.prepare.addMiddleCode(
            "{} = handle.serviceClient<{}::{}>(\"{}\");".format(
                var_serviceclient.name, self.service.namespace,
                self.service.name, self.default_service_name))

        return True, ""
Esempio n. 12
0
    def populateData(self):
        main_thread = self.associated_class.getMainThread()

        if main_thread == None:
            return False, "Unable to get the Main Thread"

        #########################
        # TRANSFORMATION FRAME #
        ########################

        # Controllo l'uso del Transformation Frame
        self.thread_uses_tf = self.setUsesTransformationFrame()

        ###############
        # Output Port #
        ###############

        # Essendo birezeizonale posso trovare la connessione sia come source che come dest
        conn_by_source = True
        process_input_port = tfs.getConnectionPortInfoBySource(
            self.process, self.type, self.input_port_name)

        if process_input_port is None:
            conn_by_source = False
            process_output_port = tfs.getConnectionPortInfoByDest(
                self.process, self.type, self.input_port_name)

        if process_input_port is None:
            return (
                False,
                "Unable to find the right binding between process requires subprogram access port and "
                "thread input port")

        if conn_by_source:
            (source_parent_name,
             source_name) = tfs.getDestFromPortInfo(process_input_port)
        else:
            (source_parent_name,
             source_name) = tfs.getSourceFromPortInfo(process_output_port)

        if source_parent_name is None or source_name is None:
            return False, "Unable to find the process provides subprogram access port name"

        self.process_port = tfs.getFeatureByName(self.process,
                                                 name=source_name)

        if self.process_port is None:
            return False, "Unable to find the process provides subprogram access port feature"

        # Dopo aver trovato la porta del process, controllo il nome di default del
        # services associato
        (topic_namespace, self.default_service_name) = tfs.getDefaultTopicName(
            self.process_port)

        if self.default_service_name == None:
            self.default_service_name = "service_name_default"
            log.warning(
                "Default Service Name not found, set as {} as default.".format(
                    self.default_service_name))

        ##################################
        ### ASN.1 Request and Response ###
        ##################################

        (aadl_namespace,
         aadl_type) = tfs.getPortDatatypeByPort(self.process_port)
        if aadl_namespace == None or aadl_type == None:
            return (False, "Unable to identify process port type")

        # Controllo se c'è un file ASN.1 associato alla porta. Se c'è allora il tipo di servizio
        # è custom e lo dovrò generare, mentre se non c'è allora è un servizio standard ROS
        port_data_info = tfs.getPortDataInfo(self.process_port)
        if port_data_info == None:
            return (False, "Unable to get the port data info for process port")

        self.asn_description = tfs.getSourceText(port_data_info)

        if self.asn_description == None:
            # @TODO: Standard Service
            log.warning("STANDARD SERVICE")
            # return (False, "Unable to find property Source_Text for the services caller with ASN.1 description")
        else:
            # Creo il servizio custom e lo associo al nodo che lo ha generato
            self.service = sfs.getServiceFromJSON(aadl_namespace, aadl_type,
                                                  self.asn_description,
                                                  self.associated_class)
            if self.service == None:
                return (False, "Error in ASN.1 parsing")

        # Genero ed aggiungo la libreria del services al nodo
        service_library = Library(self.associated_class)
        service_library.setPath("{}/{}.h".format(self.service.namespace,
                                                 self.service.name))
        self.associated_class.addLibrary(service_library)

        ##########################
        ### SERVICE SERVER VAR ###
        ##########################

        var_service_server = Variable(self.associated_class)
        var_service_server.setName("service_server_{}".format(self.name))
        var_service_server.setType(ROS_ServiceServer(self.associated_class))
        self.associated_class.addInternalVariable(var_service_server)

        ###############################
        ### SERVICE SERVER CALLBACK ###
        ###############################

        self.server_callback = Method(self.associated_class)
        self.server_callback.method_name = "{}_service_callback".format(
            self.name)
        self.server_callback.return_type = Bool(self.associated_class)
        self.server_callback.namespace = self.associated_class.class_name

        # REQUEST Parameter
        input_param_req = Variable(self.associated_class)
        input_param_req.setName("&req")
        input_param_req.setType(
            ROS_ServiceServer_Request(
                self.associated_class, "{}::{}".format(self.service.namespace,
                                                       self.service.name)))
        input_param_req.setIsParameter()

        # RESPONSE Parameter
        input_param_res = Variable(self.associated_class)
        input_param_res.setName("&res")
        input_param_res.setType(
            ROS_ServiceServer_Response(
                self.associated_class, "{}::{}".format(self.service.namespace,
                                                       self.service.name)))
        input_param_res.setIsParameter()

        self.server_callback.addInputParameter(input_param_req)
        self.server_callback.addInputParameter(input_param_res)

        ###############
        # SOURCE TEXT #
        ###############
        function = tfs.getSubcomponentByInfo(self.thread,
                                             name=self.function_name,
                                             namespace="ros",
                                             category="subprogram")
        if function is None:
            return False, "Unable to find the function subprogram"

        self.source_text_function = self.createSourceTextFileFromSourceText(
            tfs.getSourceText(function), tfs.getSourceName(function))

        if self.source_text_function is None:
            return False, "Unable to find property Source_Text or Source_Name"

        self.source_text_function.setTF(self.thread_uses_tf)

        # Aggiungo la chiamata alla funzione custom
        if self.source_text_function != None:
            self.source_text_function.addServiceReqAndRes(
                input_param_req, input_param_res)
            self.source_text_function.addLibrary(service_library)

            self.source_text_function.setFunctionType(
                Bool(self.associated_class))
            code = "return {};".format(
                self.source_text_function.generateInlineCode())
            self.server_callback.addMiddleCode(code)

        self.associated_class.addPrivateMethod(self.server_callback)

        main_thread.prepare.addMiddleCode(
            "{} = handle.advertiseService(\"{}\", {}, this);".format(
                var_service_server.name, self.default_service_name,
                self.server_callback.getThreadPointer()))

        return (True, "")
Esempio n. 13
0
    def populateData(self):
        main_thread = self.associated_class.getMainThread()

        if main_thread is None:
            return False, "Unable to get the Main Thread"

        # Ottengo le informazioni necessarie per i thread di tipo Timer:
        # - Source Text
        # - Period

        thread_function = tfs.getSubprogram(self.thread)
        if thread_function is None:
            return False, "Unable to find the right Subprogram"

        # TRANSFORMATION FRAME

        # Controllo l'uso del Transformation Frame
        self.thread_uses_tf = self.setUsesTransformationFrame()

        # Source Text

        self.source_text_function = self.createSourceTextFileFromSourceText(
            tfs.getSourceText(thread_function),
            tfs.getSourceName(thread_function))

        if self.source_text_function is None:
            return False, "Unable to find property Source_Text or Source_Name"

        self.source_text_function.setTF(self.thread_uses_tf)

        # FREQUENCY

        (period, period_unit) = tfs.getPeriod(self.thread)

        if period is None or period_unit is None:
            return False, "Unable to find property Period with relative value and unit"

        # Conversione in secondi della frequenza a partire da qualunque unità di misura
        try:
            period_quantity = ureg("{} {}".format(period, period_unit))
            period_quantity.ito(ureg.second)
            self.frequency_in_hz = 1.0 / period_quantity.magnitude
            self.period_in_seconds = period_quantity.magnitude
        except ValueError:
            return False, "Unable to convert Period in seconds"

        # TIMER
        var_timer = Variable(self.associated_class)
        var_timer.setName("timer_{}".format(self.name))
        var_timer.setType(ROS_Timer(self.associated_class))
        self.associated_class.addInternalVariable(var_timer)

        ######################
        ### TIMER CALLBACK ###
        ######################

        self.timerCallback = Method(self.associated_class)
        self.timerCallback.method_name = "{}_callback".format(self.name)
        self.timerCallback.return_type = Void(self.associated_class)
        self.timerCallback.namespace = self.associated_class.class_name

        input_par = Variable(self.associated_class)
        input_par.setIsParameter()
        input_par.setType(ROS_TimerEvent(self.associated_class))
        input_par.setName("")
        self.timerCallback.addInputParameter(input_par)

        # Aggiungo la chiamata alla funzione custom
        if self.source_text_function:
            code = "{};".format(self.source_text_function.generateInlineCode())
            self.timerCallback.addMiddleCode(code)

        self.associated_class.addPrivateMethod(self.timerCallback)

        main_thread.prepare.addMiddleCode(
            "{} = handle.createTimer(ros::Duration({}), {}, this);".format(
                var_timer.name, self.period_in_seconds,
                self.timerCallback.getThreadPointer()))

        return True, ""
Esempio n. 14
0
    def populateSubscriberData(self):
        ##################
        ### Input Port ###
        ##################

        # Ottengo la connesione che mappa la porta di input del thread subscriber
        # con quella che entra nel process
        process_input_port = tfs.getConnectionPortInfoByDest(
            self.process, self.type, self.input_port_name)
        if process_input_port == None:
            return (
                False,
                "Unable to find the right binding between process input port and thread input port"
            )

        (source_parent_name,
         source_name) = tfs.getSourceFromPortInfo(process_input_port)

        if source_parent_name == None or source_name == None:
            return (False, "Unable to find the process input port name")

        self.sub_process_port = tfs.getFeatureByName(self.process,
                                                     name=source_name)

        if self.sub_process_port == None:
            return (False,
                    "Unable to find the process input port name feature")

        ##################
        ### INPUT TYPE ###
        ##################

        (aadl_namespace,
         aadl_type) = tfs.getPortDatatypeByPort(self.sub_process_port)
        if aadl_namespace == None or aadl_type == None:
            return (False, "Unable to identify process port type")

        # Controllo se c'è un file ASN.1 associato alla porta. Se c'è allora il tipo di messaggio
        # è custom e lo dovrò generare, mentre se non c'è allora è un messaggio standard ROS
        port_data_info = tfs.getPortDataInfo(self.sub_process_port)
        if port_data_info == None:
            return (False, "Unable to get the port data info for process port")

        port_data_source_asn = tfs.getSourceText(port_data_info)
        if port_data_source_asn == None:
            # Se è None allora non c'è alcun file ASN.1 associato e quindi è un messaggio standard ROS
            raw_output_type = dt.getROSDatatypeFromAADL(
                aadl_namespace, aadl_type, self.associated_class)
            if raw_output_type == None:
                return (False,
                        "Datatype {} NOT supported".format(raw_output_type))
            else:
                self.input_type = raw_output_type
        else:
            self.custom_message = mfs.getMessageFromJSON(
                aadl_namespace, aadl_type, port_data_source_asn,
                self.associated_class)

            self.input_type = Type(self.associated_class)
            self.input_type.setTypeName(self.custom_message.name)
            self.input_type.setNamespace(self.custom_message.namespace)

        self.input_type.setConst(_const=True)
        self.input_type.setAfterTypeName("::ConstPtr&")

        # Associo la librerie del messaggio al tipo di output, sia custom che standard
        input_type_library = Library()
        input_type_library.setPath("{}/{}.h".format(self.input_type.namespace,
                                                    self.input_type.type_name))

        self.input_type.setLibrary(input_type_library)

        ########################
        ### SUBSCRIBER TOPIC ###
        ########################

        (status, desc) = self.getDefaultTopicName(self.input_port_name,
                                                  input=True)
        if status == False:
            return (status, desc)

        ##################
        ### QUEUE SIZE ###
        ##################

        queue_size_default_value = 1
        self.queue_size = tfs.getSubscriberQueueSize(
            self.thread, port_name=self.input_port_name)

        if self.queue_size == None:
            self.queue_size = queue_size_default_value
            log.info("Queue size set to default value: {}".format(
                self.queue_size))

        ######################
        ### SUBSCRIBER VAR ###
        ######################

        var_subscriber_pub = Variable(self.associated_class)
        var_subscriber_pub.setName("sub_{}".format(self.name))
        var_subscriber_pub.setType(ROS_Subscriber(self.associated_class))

        self.associated_class.addInternalVariable(var_subscriber_pub)

        ###########################
        ### SUBSCRIBER CALLBACK ###
        ###########################

        self.sub_callback = Method(self.associated_class)
        self.sub_callback.method_name = "{}_callback".format(self.name)
        self.sub_callback.return_type = Void(self.associated_class)
        self.sub_callback.namespace = self.associated_class.class_name

        self.sub_input_var = Variable(self.associated_class)
        self.sub_input_var.setType(self.input_type)
        self.sub_input_var.setName("msg")
        self.sub_input_var.setIsParameter()

        self.sub_callback.addInputParameter(self.sub_input_var)

        self.associated_class.addPrivateMethod(self.sub_callback)

        self.main_thread.prepare.addMiddleCode(
            "{} = handle.subscribe(\"{}\", {}, {}, this);".format(
                var_subscriber_pub.name, self.topic, self.queue_size,
                self.sub_callback.getThreadPointer()))

        return (True, "")
Esempio n. 15
0
    def populatePublisherData(self):
        ###################
        ### Output Port ###
        ###################

        # Ottengo la connesione che mappa la porta di input del thread subscriber
        # con quella che entra nel process
        process_output_port = tfs.getConnectionPortInfoBySource(
            self.process, self.type, self.output_port_name)
        if process_output_port == None:
            return (
                False,
                "Unable to find the right binding between process input port and thread input port"
            )

        (dest_parent_name,
         dest_name) = tfs.getDestFromPortInfo(process_output_port)

        if dest_parent_name == None or dest_name == None:
            return (False, "Unable to find the process input port name")

        self.pub_process_port = tfs.getFeatureByName(self.process,
                                                     name=dest_name)
        if self.pub_process_port == None:
            return (False,
                    "Unable to find the process input port name feature")

        ###################
        ### OUTPUT TYPE ###
        ###################

        (aadl_namespace,
         aadl_type) = tfs.getPortDatatypeByPort(self.pub_process_port)
        if aadl_namespace == None or aadl_type == None:
            return (False, "Unable to identify process port type")

        # Controllo se c'è un file ASN.1 associato alla porta. Se c'è allora il tipo di messaggio
        # è custom e lo dovrò generare, mentre se non c'è allora è un messaggio standard ROS
        port_data_info = tfs.getPortDataInfo(self.pub_process_port)
        if port_data_info == None:
            return (False, "Unable to get the port data info for process port")

        port_data_source_asn = tfs.getSourceText(port_data_info)
        if port_data_source_asn == None:
            # Se è None allora non c'è alcun file ASN.1 associato e quindi è un messaggio standard ROS
            raw_output_type = dt.getROSDatatypeFromAADL(
                aadl_namespace, aadl_type, self.associated_class)
            if raw_output_type == None:
                return (False,
                        "Datatype {} NOT supported".format(raw_output_type))
            else:
                self.output_type = raw_output_type
        else:
            self.custom_message = mfs.getMessageFromJSON(
                aadl_namespace, aadl_type, port_data_source_asn,
                self.associated_class)

            self.output_type = Type(self.associated_class)
            self.output_type.setTypeName(self.custom_message.name)
            self.output_type.setNamespace(self.custom_message.namespace)

        # Associo la librerie del messaggio al tipo di output, sia custom che standard
        output_type_library = Library()
        output_type_library.setPath("{}/{}.h".format(
            self.output_type.namespace, self.output_type.type_name))

        self.output_type.setLibrary(output_type_library)

        #############
        ### TOPIC ###
        #############

        (status, desc) = self.getDefaultTopicName(self.output_port_name,
                                                  output=True)
        if not status:
            return status, desc

        #####################
        ### PUBLISHER VAR ###
        #####################

        self.var_publisher_pub = Variable(self.associated_class)
        self.var_publisher_pub.setName("pub_{}".format(self.name))
        self.var_publisher_pub.setType(ROS_Publisher(self.associated_class))
        self.associated_class.addInternalVariable(self.var_publisher_pub)

        self.main_thread.prepare.addMiddleCode(
            "{} = handle.advertise<{}>(\"{}\", 10);".format(
                self.var_publisher_pub.name, self.output_type.generateCode(),
                self.topic))

        return True, ""
def generateSystemCode(system_root, system_parent):
    # Generando il system si generano anche i file CMakeLists e PackageXML
    # Viene generata tutto l'albero delle cartelle e viene resettato se necessario
    namespace = tfs.getNamespace(system_root)

    system = sm.getSystemForNamespace(namespace)
    if system is None:
        system = System(system_root)
        sm.addSystem(system)

    # Se il system non ha un launch file associato e serve crearlo, allora lo creo
    # Il launch file a questo punto è vuoto
    if system.launch_file is None:
        system.createLaunchFile()

        # Se ho un genitore, ovvero un system che mi ha incluso,
        # lo avviso che dovrà includermi
        if system_parent:
            if system_parent.launch_file:
                system_parent.launch_file.addSubSystem(system.launch_file)

    # Ricerco tutti i processi all'interno del system
    processes = system_root.findall("./" + XMLTags.tags['TAG_SUBCOMPONENTS'] +
                                    "/" + XMLTags.tags['TAG_SUBCOMPONENT'] +
                                    "/" + "[" + XMLTags.tags['TAG_CATEGORY'] +
                                    "='process']" + "[" +
                                    XMLTags.tags['TAG_NAMESPACE'] + "='" +
                                    system.namespace + "']")

    # Scorro ogni processo. Per ogni processo controllo i subcomponent: in base alle varie tipologie
    # di subcomponent avvio la generazione di diversi nodi ROS
    for process in processes:
        threads = process.findall("./" + XMLTags.tags['TAG_SUBCOMPONENTS'] +
                                  "/" + XMLTags.tags['TAG_SUBCOMPONENT'] +
                                  "/" + "[" + XMLTags.tags['TAG_CATEGORY'] +
                                  "='thread']")

        # Cerco il main thread, che formerà la base per tutti gli altri thread.
        main_thread = process.find("./" + XMLTags.tags['TAG_SUBCOMPONENTS'] +
                                   "/" + XMLTags.tags['TAG_SUBCOMPONENT'] +
                                   "/" + "[" + XMLTags.tags['TAG_CATEGORY'] +
                                   "='thread']" + "/" + "[" +
                                   XMLTags.tags['TAG_NAME'] +
                                   "='main_thread']" + "/" + "[" +
                                   XMLTags.tags['TAG_NAMESPACE'] + "='ros']")
        if main_thread:
            thread_type = (tfs.getType(main_thread)).lower()

            p = AADLProcess(process, system_root, system)
            renameExistingNodeClass(p, system.system_folder)

            gen_main_thread = createNewThread(
                system_root, process, main_thread,
                getPythonClassFromAADLThreadType(thread_type), p)
            p.threads.append(gen_main_thread)

            for thread in threads:
                # name        = (tfs.getName(thread)).lower()
                thread_type = (tfs.getType(thread)).lower()
                namespace = (tfs.getNamespace(thread)).lower()

                if (namespace == "ros" or namespace == "global_state_machine"
                    ) and not isMainThread(thread_type):
                    new_thread = createNewThread(
                        system_root, process, thread,
                        getPythonClassFromAADLThreadType(thread_type), p)
                    if new_thread:
                        p.threads.append(new_thread)

            p.addTransformationFrameComponent()
            system.addNode(p)
Esempio n. 17
0
    def populateData(self):
        main_thread = self.associated_class.getMainThread()

        if main_thread == None:
            return (False, "Unable to get the Main Thread")

        # Ottengo le informazioni necessarie per i thread di tipo Publisher:
        # - Source Text
        # - Period

        thread_function = tfs.getSubprogram(self.thread)
        if thread_function == None:
            return (False, "Unable to find the right Subprogram")

        ############################
        ### TRANSFORMATION FRAME ###
        ############################

        # Controllo l'uso del Transformation Frame
        self.thread_uses_tf = self.setUsesTransformationFrame()

        ###################
        ### Output Port ###
        ###################

        # Ottengo la connesione che mappa la porta di input del thread subscriber
        # con quella che entra nel process
        process_output_port = tfs.getConnectionPortInfoBySource(self.process, self.type, self.output_port_name)
        if process_output_port is None:
            return False, "Unable to find the right binding between process input port and thread input port"

        (dest_parent_name, dest_name) = tfs.getDestFromPortInfo(process_output_port)

        if dest_parent_name is None or dest_name is None:
            return False, "Unable to find the process input port name"

        self.process_port = tfs.getFeatureByName(self.process, name=dest_name)
        if self.process_port is None:
            return False, "Unable to find the process input port name feature"

        (aadl_namespace, aadl_type) = tfs.getPortDatatypeByPort(self.process_port)
        if aadl_namespace is None or aadl_type is None:
            return False, "Unable to identify process port type"

        # Controllo se c'è un file ASN.1 associato alla porta. Se c'è allora il tipo di messaggio
        # è custom e lo dovrò generare, mentre se non c'è allora è un messaggio standard ROS
        port_data_info = tfs.getPortDataInfo(self.process_port)
        if port_data_info is None:
            return False, "Unable to get the port data info for process port"

        port_data_source_asn = tfs.getSourceText(port_data_info)
        if port_data_source_asn is None:
            # Se è None allora non c'è alcun file ASN.1 associato e quindi è un messaggio standard ROS
            raw_output_type = dt.getROSDatatypeFromAADL(aadl_namespace, aadl_type, self.associated_class)
            if raw_output_type is None:
                return False, "Datatype {} NOT supported".format(raw_output_type)
            else:
                self.output_type = raw_output_type
        else:
            self.custom_message = mfs.getMessageFromJSON(aadl_namespace,
                                                         aadl_type,
                                                         port_data_source_asn,
                                                         self.associated_class)

            self.output_type = Type(self.associated_class)
            self.output_type.setTypeName(self.custom_message.name)
            self.output_type.setNamespace(self.custom_message.namespace)

        # Associo la librerie del messaggio al tipo di output, sia custom che standard
        output_type_library = Library()
        output_type_library.setPath("{}/{}.h".format(self.output_type.namespace, self.output_type.type_name))

        self.output_type.setLibrary(output_type_library)

        ###################
        ### Source Text ###
        ###################

        self.source_text_function = self.createSourceTextFileFromSourceText(tfs.getSourceText(thread_function),
                                                                            tfs.getSourceName(thread_function))

        if self.source_text_function is None:
            return False, "Unable to find property Source_Text or Source_Name"

        self.source_text_function.setTF(self.thread_uses_tf)
        self.source_text_function.setFunctionType(self.output_type)

        #################
        ### FREQUENCY ###
        #################

        (period, period_unit) = tfs.getPeriod(self.thread)

        if period is None or period_unit is None:
            return False, "Unable to find property Period with relative value and unit"

        # Conversione in secondi della frequenza a partire da qualunque unità di misura
        try:
            period_quantity = ureg("{} {}".format(period, period_unit))
            period_quantity.ito(ureg.second)
            self.frequency_in_hz = 1.0 / period_quantity.magnitude
            self.period_in_seconds = period_quantity.magnitude
        except ValueError:
            return False, "Unable to convert Period in seconds"

        # param_freq = Variable( self.associated_class )
        # param_freq.setName( "frequency_{}".format(self.name) )
        # param_freq.setType( Int( self.associated_class ))
        # self.associated_class.addParameter( param_freq )

        #############
        ### TOPIC ###
        #############

        (status, desc) = self.getDefaultTopicName(self.output_port_name, output=True)
        if status is False:
            return status, desc

        #####################
        ### PUBLISHER VAR ###
        #####################

        var_publisher_pub = Variable(self.associated_class)
        var_publisher_pub.setName("pub_{}".format(self.name))
        var_publisher_pub.setType(ROS_Publisher(self.associated_class))
        self.associated_class.addInternalVariable(var_publisher_pub)

        #######################
        ### PUBLISHER TIMER ###
        #######################

        var_timer_pub = Variable(self.associated_class)
        var_timer_pub.setName("timer_{}".format(self.name))
        var_timer_pub.setType(ROS_Timer(self.associated_class))
        self.associated_class.addInternalVariable(var_timer_pub)

        ##########################
        ### PUBLISHER CALLBACK ###
        ##########################

        self.publisherCallback = Method(self.associated_class)
        self.publisherCallback.method_name = "{}_callback".format(self.name)
        self.publisherCallback.return_type = Void(self.associated_class)
        self.publisherCallback.namespace = self.associated_class.class_name

        input_par = Variable(self.associated_class)
        input_par.setIsParameter()
        input_par.setType(ROS_TimerEvent(self.associated_class))
        input_par.setName("")
        self.publisherCallback.addInputParameter(input_par)

        # Aggiungo la chiamata alla funzione custome
        if self.source_text_function:
            code = "{}.publish({});".format(var_publisher_pub.name,
                                            self.source_text_function.generateInlineCode())
            self.publisherCallback.addMiddleCode(code)

        self.associated_class.addPrivateMethod(self.publisherCallback)

        main_thread.prepare.addMiddleCode("{} = handle.advertise < {} > (\"{}\", 10);"
                                          .format(var_publisher_pub.name, self.output_type.generateCode(), self.topic))

        main_thread.prepare.addMiddleCode("{} = handle.createTimer(ros::Duration({}), {}, this);"
                                          .format(var_timer_pub.name, self.period_in_seconds,
                                                  self.publisherCallback.getThreadPointer()))

        return True, ""