def __init__(self, _associated_class): super().__init__(_associated_class) self.namespace = self.associated_class.class_name self.method_name = "errorHandling" self.return_type = Void(self.associated_class) # @TODO: Codice provvisorio self.addTopCode("ROSNode::errorHandling();")
def __init__(self, _associated_class): super().__init__(_associated_class) self.namespace = self.associated_class.class_name self.method_name = "tearDown" self.return_type = Void(self.associated_class) self.addTopCode("ROS_INFO(\"Node is shutting down\");") self.addBottomCode("return;")
def createSourceTextFileFromSourceText(self, source_text, source_name, function_type=Void()): if source_text is None or source_name is None: return None source_text_file = self.associated_class.getSourceFile(source_text) if source_text_file is None: source_text_file = SourceTextFile(self.associated_class, source_text) self.associated_class.addSourceFile(source_text_file) # Se ho già la funzione presente nel file, non la devo ri-creare if source_text_file.hasFunctionFromName(source_name): source_text_function = source_text_file.getFunctionFromName(source_name) else: source_text_function = SourceTextFunction(self.associated_class, source_text_file, source_name) source_text_function.setFunctionType(function_type) source_text_file.addFunction(source_text_function) return source_text_function
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, ""
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, "")
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, ""