예제 #1
0
    def load_vn_from_module(self, module, checked=False, **kwargs):
        """Load virtual node from an imported module.

        Instantiates a virtual node from a class defined in provided module.
        Such module must have been already imported and should contain only one
        virtual node class that is a child of 'nodes.BaseVirtualNode'. That
        last feature can be checked passing an argument 'checked' as False.

        Args:
            module: Module containing virtual node's definition.
            checked (boolean): A flag indicating whether module's content (only
                one BaseVirtualNode's child class) has been checked or not.
        """
        if not checked:
            if self.is_vn_ill_defined(module.__name__):
                notice(
                    self, "Provided module '" + module.__name__ +
                    ".py' was ill defined and could not be loaded.")
                return

        for name in dir(module):
            cls = getattr(module, name)
            if inspect.isclass(cls):
                if "BaseVirtualNode" in str(cls.__mro__[-2]):
                    self.vn_class = cls
                else:
                    notice(self, "Error - Virtual node class ill defined.")
                    return

        self.set_node(self.vn_class, **kwargs)
예제 #2
0
    def wait_for_new_port(self, filter_term=None, time_limit=10):
        """Wait for a new port to be created.

        This function waits for the user to connect an interface device and
        returns its new serial port.

        Args:
            filter_term (str): Optional serial port filter, depends on
                interface type and operating system.
            time_limit (float): Maximum number of seconds to wait for a new
                port to be created.

        Returns:
            A list of new serial ports. False, otherwise.

        """
        timer_count = 0
        old_ports = scan_serial_ports(filter_term)
        num_old_ports = len(old_ports)
        while True:
            time.sleep(0.25)
            timer_count += 0.25
            if timer_count > time_limit:
                notice(self.owner,
                       'TIMEOUT while trying to acquire a new port.')
                return False
            new_ports = scan_serial_ports(filter_term)
            num_new_ports = len(new_ports)
            if num_new_ports < num_old_ports:
                # A device has been unplugged, update info
                old_ports = list(new_ports)
                num_old_ports = num_new_ports
            elif num_new_ports > num_old_ports:
                # Returns all ports that just appeared
                return list(set(new_ports) - set(old_ports))
예제 #3
0
    def acquire_port_and_connect(self, interface_type):
        """Acquire a serial port and connect to it.

        Tries to detect a serial port based on the provided interface type.
        If no serial port is detected, it waits some seconds (10 by default)
        for a new one to be created.

        Args:
             interface_type (str): Type of interface.

        Returns:
            Call to connect function if a port was detected. Exits, otherwise.
        """
        serial_filter = self.get_serial_filter_terms(interface_type)
        available_ports = get_available_serial_ports(serial_filter)
        if len(available_ports) == 1:
            # Connects to the only available port that matches the filter.
            self.portName = available_ports[0]
            return self.connect()
        else:
            notice(
                self, "Trying to acquire serial port. You have 10 seconds to "
                "plug an interface in.")
            new_ports = self.wait_for_new_port(serial_filter)
            if new_ports:
                if len(new_ports) > 1:
                    notice(
                        self.owner,
                        "Could not acquire. Multiple ports plugged in "
                        "simultaneously.")
                    return
                else:
                    self.portName = new_ports[0]
                    return self.connect()
예제 #4
0
    def transmit(self, data):
        """Add data to transmit queue.

        As a thread handles data transmission, it continuously checks the
        transmit queue and sends data when added by this function.
        String data is converted to a list by default.
        """
        if self.isConnected:
            self.transmitQueue.put(data)
        else:
            notice(self, 'Serial interface is not connected.')
예제 #5
0
 def __getattr__(self, attribute):
     """Forward any unsupported call to the shell onto the node."""
     if self.node is not None:  # Shell contains a node.
         if hasattr(self.node,
                    attribute):  # node contains requested attribute
             return getattr(self.node, attribute)
         else:
             notice(self, "Node does not have requested attribute.")
             raise AttributeError(attribute)
     else:
         notice(self, "Node has not been initialized.")
         raise AttributeError(attribute)
예제 #6
0
 def publish_settings(self):
     init_message = ''
     if self.name:
         init_message += "Name: " + self.name + '\n'
     if self.interface:
         init_message += "Provided interface: True" + '\n'
     else:
         init_message += "Provided interface: False" + '\n'
     if self.persistence:
         init_message += "Persistence file: " + self.persistence.filename + '\n'
     else:
         init_message += "Persistence file: False" + '\n'
     notice(self, init_message)
예제 #7
0
    def load_vn_from_url(self, url, **kwargs):
        """Load virtual node from a url.

        This functions gets the text from a provided URL, imports it as a
        module and loads the defined virtual node.

        Args:
             url (str): URL directing to virtual node's definition.
        """
        resp = requests.get(url)
        notice(self, resp.text)
        vn_imported_module = self.import_vn_module(resp.text)
        self.load_vn_from_module(vn_imported_module, checked=True, **kwargs)
예제 #8
0
        def serialize(self, packet):
            """Convert packet into a string for transmission over a serial port.

            Uses ASCII characters.

            Returns:
                Packet as string if it was a list or a string. False, otherwise.
            """
            if type(packet) == list:
                return ''.join([chr(byte) for byte in packet])
            elif type(packet) == str:
                return packet
            else:
                notice(self,
                       "Error: Packet must be either a list or a string.")
                return False
예제 #9
0
    def set_node(self, vn_class, **kwargs):
        """Sets contained or linked node.

        Creates an instance of selected virtual node class and executes its
        'init()' method.
        Owner, name and interface from this shell are passed to contained node.

        Args:
            vn_class (Class): Virtual node class to be instantiated.
            kwargs: Arguments to be passed onto the virtual node's initialization.
        """
        self.node = vn_class(self.owner, **kwargs)
        notice(self, "Node assigned to '" + self.name + "' node shell.")
        self.node.shell = self
        self.node.name = self.name
        self.node.interface = self.interface
        self.node.init(**self.node.initKwargs)
예제 #10
0
    def init_after_set(self):
        """Initialize after setting.

        Begins connection procedure. First, it tries to connect to provided
        port name; if there is no port name, it waits for a new port to be
        created based on a provided interface type.
        """
        if self.portName:
            self.connect(self.portName)
        elif self.interfaceType:
            # if an interface type is provided, auto-acquire
            self.acquire_port_and_connect(self.interfaceType)
        else:
            notice(
                self,
                "Serial interface could not be initialized. A port name or an "
                "interface type are required.")
예제 #11
0
    def __getattr__(self, attribute):
        """Forward attribute calls to the contained interface.

        Args:
            attribute: Contained interface's attribute to be called.

        Returns:
            Contained interfaces's attribute.
        """
        if self.contained_interface is not None:
            if hasattr(self.contained_interface, attribute):
                return getattr(self.contained_interface, attribute)
            else:
                notice(self, "Interface does not have requested attribute.")
                raise AttributeError(attribute)
        else:
            notice(self, "Interface shell is empty.")
            raise AttributeError(attribute)
예제 #12
0
        def run(self):
            """Define code to be ran by the transmit thread.

            Gets a packet from transmit queue, converts it into a string and
            transmits it.
            """
            while True:
                transmit_state, transmit_packet = self.get_transmit_packet()
                if transmit_state:
                    if self.port:
                        self.port.write(
                            self.serialize(transmit_packet).encode('utf-8'))
                    else:
                        notice(
                            self, "Cannot transmit. No serial port "
                            "initialized.")
                time.sleep(0.0005)
            pass
예제 #13
0
    def is_vn_ill_defined(self, vn_module):
        """Check whether a virtual node is ill defined or not.

        Makes sure that selected virtual node contains one and only one
        user-defined virtual machine class, child of 'nodes.BaseVirtualNode'
        class.

        Args:
            vn_module: Virtual node module to be analyzed.

        Returns:
            True when selected module contains none or more than a unique
            virtual node. False otherwise.
        """
        num_of_vn_cls = 0
        for name, class_data in sorted(pyclbr.readmodule(vn_module).items(),
                                       key=lambda x: x[1].lineno):
            supers_list = []
            if hasattr(class_data, 'super'):
                class_super = class_data.super[0]
                if hasattr(class_super, 'name'):
                    while class_super != 'object':
                        supers_list.append(class_super.name)
                        class_super = class_super.super[0]
                    supers_list.append('object')
                else:
                    supers_list.append(class_super)
            if any('BaseVirtualNode' in super_ for super_ in supers_list):
                num_of_vn_cls += 1

        if num_of_vn_cls == 0:
            notice(self, "Error: No virtual node defined.")
            return True
        elif num_of_vn_cls > 1:
            notice(
                self, "Error: More than a unique virtual node defined in a "
                "single file.")
            return True

        return False
예제 #14
0
    def connect(self, port_name=None):
        """Connect to serial port.

        Connects to specified port name. Tries to connect to port assigned on
        instantiation if no port is specified as argument.

        Args:
            port_name (str): Name of serial port.
        """
        if port_name:
            port = port_name
        elif self.portName:
            port = self.portName
        else:
            notice(self, 'No port name provided.')
            return

        try:
            self.port = serial.Serial(port,
                                      self.baudRate,
                                      timeout=self.timeOut)
        except serial.SerialException:
            notice(self, "Error when opening serial port " + str(port))
            return

        self.port.flushInput()
        self.port.flushOutput()
        notice(self, "Port " + str(port) + " connected successfully.")
        # Some serial ports need some time between opening and transmission
        time.sleep(2)
        self.isConnected = True
        self.start_transmitter()
예제 #15
0
    def get_serial_filter_terms(self, interface_type=None):
        """Get filter terms for serial ports.

        According to the operating system, selects a type of filter and the
        filter term.
        For example, in the case of Arduino, the type is 'manufacturer' and the
        filter term is 'Arduino'. This implementation allows the inclusion of
        new interfaces.

        Args:
            interface_type (str): Type of interface, 'ftdi' for FTDI devices,
                'Arduino' for Arduino and 'generic serial' for others.

        Returns:
            A list of filter type and filter term respectively, if found on
            the dictionary. False, otherwise.

        Note:
            Currently, the type of filter should be one attribute of
            'serial.tools.list_ports.ListPortInfo' class, supported by your
            operating system (Windows, Linux os MacOS).

        Note:
            The use of interface type 'genericSerial' should be avoided
            because many devices could share the provided filter term.
        """
        ftdi_terms = {
            'Windows': ['manufacturer', 'FTDI'],
            'Linux': ['manufacturer', 'FTDI'],
            'Darwin': ['manufacturer', 'FTDI']
        }
        arduino_terms = {
            'Windows': ['manufacturer', 'Arduino'],
            'Linux': ['manufacturer', 'Arduino'],
            'Darwin': ['manufacturer', 'Arduino']
        }
        generic_serial_terms = {
            'Windows': ['device', 'COM'],
            'Linux': ['device', 'tty'],
            'Darwin': ['device', 'tty.']
        }
        terms_dict = {
            'ftdi': ftdi_terms,
            'arduino': arduino_terms,
            'genericSerial': generic_serial_terms
        }
        op_sys = platform.system()  # nominally detects the system
        if interface_type in terms_dict:
            if op_sys in terms_dict[interface_type]:
                return terms_dict[interface_type][op_sys]
            else:
                notice(
                    self,
                    "Operating system support not found for interface type '" +
                    interface_type + "'")
                return False
        else:
            notice(
                self, "Interface support not found for interface type '" +
                interface_type + "'")
            return False
예제 #16
0
 def do(self):
     notice(self, "It does work.")