Ejemplo n.º 1
0
    def __init__(
        self,
        modi_version=1,
        conn_type="",
        verbose=False,
        port=None,
        network_uuid="",
        virtual_modules=None,
    ):
        if virtual_modules and conn_type != "vir":
            raise ValueError(
                "Virtual modules can only be defined in virtual connection")
        self._modules = list()
        self._topology_data = dict()

        self._conn = self.__init_task(
            conn_type,
            verbose,
            port,
            network_uuid,
        )

        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        print('Start initializing connected MODI modules')
        self._exe_thrd.start()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)

        init_time = time.time()
        while not self._topology_manager.is_topology_complete():
            time.sleep(0.1)
            if time.time() - init_time > 5:
                print("MODI init timeout over. "
                      "Check your module connection.")
                break
        check_complete(self)
        print("MODI modules are initialized!")

        bad_modules = (self.__wait_user_code_check()
                       if conn_type != 'ble' else [])
        if bad_modules:
            cmd = input(f"{[str(module) for module in bad_modules]} "
                        f"has user code in it.\n"
                        f"Reset the user code? [y/n] ")
            if 'y' in cmd:
                self.close()
                modules_to_reset = filter(lambda m: m.is_up_to_date,
                                          bad_modules)
                modules_to_update = filter(lambda m: not m.is_up_to_date,
                                           bad_modules)
                reset_module_firmware(
                    tuple(module.id for module in modules_to_reset))
                update_module_firmware(
                    tuple(module.id for module in modules_to_update))
                self.open()
        atexit.register(self.close)
Ejemplo n.º 2
0
    def __init__(self,
                 conn_mode: str = "",
                 verbose: bool = False,
                 port: str = None,
                 uuid=""):
        if conn_mode == 'ble' and 'darwin' in sys.platform:
            print("BLE Connection not supported on macOS")
            exit(0)
        self._modules = list()
        self._topology_data = dict()

        self._conn = self.__init_task(conn_mode, verbose, port, uuid)

        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        print('Start initializing connected MODI modules')
        self._exe_thrd.start()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)

        init_time = time.time()
        while not self._topology_manager.is_topology_complete():
            time.sleep(0.1)
            if time.time() - init_time > 5:
                print("MODI init timeout over. "
                      "Check your module connection.")
                break
        check_complete(self)
        print("MODI modules are initialized!")

        bad_modules = (self.__wait_user_code_check()
                       if conn_mode != 'ble' else [])
        if bad_modules:
            cmd = input(f"{[str(module) for module in bad_modules]} "
                        f"has user code in it.\n"
                        f"Reset the user code? [y/n] ")
            if 'y' in cmd:
                self.close()
                modules_to_reset = filter(lambda m: m.is_up_to_date,
                                          bad_modules)
                modules_to_update = filter(lambda m: not m.is_up_to_date,
                                           bad_modules)
                reset_module_firmware(
                    tuple(module.id for module in modules_to_reset))
                update_module_firmware(
                    tuple(module.id for module in modules_to_update))
                self.open()
        atexit.register(self.close)
Ejemplo n.º 3
0
class MODI:
    network_uuids = {}

    def __call__(cls, *args, **kwargs):
        network_uuid = kwargs.get('network_uuid')
        conn_type = kwargs.get('conn_type')
        if conn_type != 'ble':
            return super(MODI, cls).__call__(*args, **kwargs)
        if not network_uuid:
            raise ValueError('Should input a valid network uuid!')
        if network_uuid not in cls.network_uuids:
            cls.network_uuids[network_uuid] = \
                super(MODI, cls).__call__(*args, **kwargs)
        return cls.network_uuids[network_uuid]

    def __init__(
        self,
        modi_version=1,
        conn_type="",
        verbose=False,
        port=None,
        network_uuid="",
        virtual_modules=None,
    ):
        if virtual_modules and conn_type != "vir":
            raise ValueError(
                "Virtual modules can only be defined in virtual connection")
        self._modules = list()
        self._topology_data = dict()

        self._conn = self.__init_task(
            conn_type,
            verbose,
            port,
            network_uuid,
        )

        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        print('Start initializing connected MODI modules')
        self._exe_thrd.start()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)

        init_time = time.time()
        while not self._topology_manager.is_topology_complete():
            time.sleep(0.1)
            if time.time() - init_time > 3:
                print('MODI init timeout over. Check your module connection.')
                break
        check_complete(self)
        print("MODI modules are initialized!")

        bad_modules = (self.__wait_user_code_check()
                       if conn_type != 'ble' else [])
        if bad_modules:
            cmd = input(f"{[str(module) for module in bad_modules]} "
                        f"has user code in it.\n"
                        f"Reset the user code? [y/n] ")
            if 'y' in cmd:
                self.close()
                modules_to_reset = filter(lambda m: m.is_up_to_date,
                                          bad_modules)
                modules_to_update = filter(lambda m: not m.is_up_to_date,
                                           bad_modules)
                reset_module_firmware(
                    tuple(module.id for module in modules_to_reset))
                update_module_firmware(
                    tuple(module.id for module in modules_to_update))
                self.open()
        atexit.register(self.close)

    @staticmethod
    def __init_logger():
        logger = logging.getLogger(f'PyMODI (v{__version__}) Logger')
        logger.setLevel(logging.DEBUG)

        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        file_handler = logging.FileHandler('pymodi.log')
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(formatter)

        logger.addHandler(file_handler)
        return logger

    def __wait_user_code_check(self):
        def is_not_checked(module):
            return module.user_code_status < 0

        while list(filter(is_not_checked, self._modules)):
            time.sleep(0.1)
        bad_modules = []
        for module in self._modules:
            if module.has_user_code:
                bad_modules.append(module)
        return bad_modules

    def __init_task(
        self,
        conn_type,
        verbose,
        port,
        network_uuid,
    ):
        if not conn_type:
            is_can = not is_network_module_connected() and is_on_pi()
            conn_type = 'can' if is_can else 'ser'

        if conn_type == 'ser':
            return im('modi.task.ser_task').SerTask(verbose, port)
        elif conn_type == 'soc':
            return im('modi.task.soc_task').SocTask(verbose, port)
        elif conn_type == 'vir':
            return im('modi.task.vir_task').VirTask(verbose, port)
        elif conn_type == 'can':
            return im('modi.task.can_task').CanTask(verbose)
        elif conn_type == 'ble':
            if not network_uuid:
                raise ValueError('Network UUID not specified!')
            self.network_uuids[network_uuid] = self
            mod_path = {
                'win32': 'modi.task.ble_task.ble_task_mac',
                'linux': 'modi.task.ble_task.ble_task_rpi',
                'darwin': 'modi.task.ble_task.ble_task_mac',
            }.get(sys.platform)
            return im(mod_path).BleTask(verbose, network_uuid)
        else:
            raise ValueError(f'Invalid conn mode: {conn_type}')

    def open(self):
        atexit.register(self.close)
        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        self._conn.open_conn()
        self._exe_thrd.start()

    def close(self):
        atexit.unregister(self.close)
        print("Closing MODI connection...")
        self._exe_thrd.close()
        self._conn.close_conn()

    def send(self, message):
        """Low level method to send json pkt directly to modules

        :param message: Json packet to send
        :return: None
        """
        self._conn.send_nowait(message)

    def recv(self):
        """Low level method to receive json pkt directly from modules

        :return: Json msg received
        :rtype: str if msg exists, else None
        """
        return self._conn.recv()

    def print_topology_map(self, print_id=False):
        """Prints out the topology map

        :param print_id: if True, the result includes module id
        :return: None
        """
        self._topology_manager.print_topology_map(print_id)

    @property
    def modules(self) -> ModuleList:
        """Module List of connected modules except network module.
        """
        return ModuleList(self._modules)

    @property
    def networks(self) -> ModuleList:
        return ModuleList(self._modules, 'network')

    @property
    def buttons(self) -> ModuleList:
        """Module List of connected Button modules.
        """
        return ModuleList(self._modules, 'button')

    @property
    def dials(self) -> ModuleList:
        """Module List of connected Dial modules.
        """
        return ModuleList(self._modules, "dial")

    @property
    def displays(self) -> ModuleList:
        """Module List of connected Display modules.
        """
        return ModuleList(self._modules, "display")

    @property
    def envs(self) -> ModuleList:
        """Module List of connected Env modules.
        """
        return ModuleList(self._modules, "env")

    @property
    def gyros(self) -> ModuleList:
        """Module List of connected Gyro modules.
        """
        return ModuleList(self._modules, "gyro")

    @property
    def irs(self) -> ModuleList:
        """Module List of connected Ir modules.
        """
        return ModuleList(self._modules, "ir")

    @property
    def leds(self) -> ModuleList:
        """Module List of connected Led modules.
        """
        return ModuleList(self._modules, "led")

    @property
    def mics(self) -> ModuleList:
        """Module List of connected Mic modules.
        """
        return ModuleList(self._modules, "mic")

    @property
    def motors(self) -> ModuleList:
        """Module List of connected Motor modules.
        """
        return ModuleList(self._modules, "motor")

    @property
    def speakers(self) -> ModuleList:
        """Module List of connected Speaker modules.
        """
        return ModuleList(self._modules, "speaker")

    @property
    def ultrasonics(self) -> ModuleList:
        """Module List of connected Ultrasonic modules.
        """
        return ModuleList(self._modules, "ultrasonic")
Ejemplo n.º 4
0
 def open(self):
     atexit.register(self.close)
     self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                              self._conn)
     self._conn.open_conn()
     self._exe_thrd.start()
Ejemplo n.º 5
0
    def __init__(self,
                 nb_modules: int = None,
                 conn_mode: str = "serial",
                 module_uuid: str = "",
                 test: bool = False,
                 verbose: bool = False,
                 port: str = None):
        self._modules = list()
        self._module_ids = dict()
        self._topology_data = dict()

        self.__lazy = not nb_modules

        self._recv_q = CommunicationQueue()
        self._send_q = CommunicationQueue()

        self._conn_proc = None
        self._exe_thrd = None

        # Init flag used to notify initialization of MODI modules
        module_init_flag = th.Event()

        # If in test run, do not create process and thread
        if test:
            return

        init_flag = mp.Event()

        self._conn_proc = ConnProc(self._recv_q, self._send_q, conn_mode,
                                   module_uuid, verbose, init_flag, port)
        self._conn_proc.daemon = True
        try:
            self._conn_proc.start()
        except RuntimeError:
            if os.name == 'nt':
                print('\nProcess initialization failed!\nMake sure you are '
                      'using\n    if __name__ == \'__main__\' \n '
                      'in the main module.')
            else:
                traceback.print_exc()
            exit(1)

        MODI.__conn_procs.append(self._conn_proc.pid)

        self._child_watch = th.Thread(target=self.watch_child_process)
        self._child_watch.daemon = True
        self._child_watch.start()

        if nb_modules:
            init_flag.wait()

        self._firmware_updater = FirmwareUpdater(self._send_q)

        init_flag = th.Event()

        self._exe_thrd = ExeThrd(self._modules, self._module_ids,
                                 self._topology_data, self._recv_q,
                                 self._send_q, module_init_flag, nb_modules,
                                 self._firmware_updater, init_flag)
        self._exe_thrd.daemon = True
        self._exe_thrd.start()
        if nb_modules:
            init_flag.wait()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)
        if nb_modules:
            module_init_flag.wait()
            if not module_init_flag.is_set():
                raise Exception("Modules are not initialized properly!")
                exit(1)
            print("MODI modules are initialized!")
            check_complete(self)

        while not self._topology_manager.is_topology_complete(self._exe_thrd):
            time.sleep(0.1)
Ejemplo n.º 6
0
class MODI:
    """
    Example:
    >>> import modi
    >>> bundle = modi.MODI()
    """

    # Keeps track of all the connection processes spawned
    __conn_procs = []

    def __init__(self,
                 nb_modules: int = None,
                 conn_mode: str = "serial",
                 module_uuid: str = "",
                 test: bool = False,
                 verbose: bool = False,
                 port: str = None):
        self._modules = list()
        self._module_ids = dict()
        self._topology_data = dict()

        self.__lazy = not nb_modules

        self._recv_q = CommunicationQueue()
        self._send_q = CommunicationQueue()

        self._conn_proc = None
        self._exe_thrd = None

        # Init flag used to notify initialization of MODI modules
        module_init_flag = th.Event()

        # If in test run, do not create process and thread
        if test:
            return

        init_flag = mp.Event()

        self._conn_proc = ConnProc(self._recv_q, self._send_q, conn_mode,
                                   module_uuid, verbose, init_flag, port)
        self._conn_proc.daemon = True
        try:
            self._conn_proc.start()
        except RuntimeError:
            if os.name == 'nt':
                print('\nProcess initialization failed!\nMake sure you are '
                      'using\n    if __name__ == \'__main__\' \n '
                      'in the main module.')
            else:
                traceback.print_exc()
            exit(1)

        MODI.__conn_procs.append(self._conn_proc.pid)

        self._child_watch = th.Thread(target=self.watch_child_process)
        self._child_watch.daemon = True
        self._child_watch.start()

        if nb_modules:
            init_flag.wait()

        self._firmware_updater = FirmwareUpdater(self._send_q)

        init_flag = th.Event()

        self._exe_thrd = ExeThrd(self._modules, self._module_ids,
                                 self._topology_data, self._recv_q,
                                 self._send_q, module_init_flag, nb_modules,
                                 self._firmware_updater, init_flag)
        self._exe_thrd.daemon = True
        self._exe_thrd.start()
        if nb_modules:
            init_flag.wait()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)
        if nb_modules:
            module_init_flag.wait()
            if not module_init_flag.is_set():
                raise Exception("Modules are not initialized properly!")
                exit(1)
            print("MODI modules are initialized!")
            check_complete(self)

        while not self._topology_manager.is_topology_complete(self._exe_thrd):
            time.sleep(0.1)

    def update_module_firmware(self) -> None:
        """Updates firmware of connected modules"""
        print("Request to update firmware of connected MODI modules.")
        self._firmware_updater.reset_state()
        self._firmware_updater.request_to_update_firmware()
        self._firmware_updater.update_event.wait()
        print("Module firmwares have been updated!")

    def watch_child_process(self) -> None:
        while self._conn_proc.is_alive():
            time.sleep(0.1)
        for pid in MODI.__conn_procs:
            try:
                os.kill(pid, signal.SIGTERM)
            except PermissionError:
                continue
            except ProcessLookupError:
                continue
        os.kill(os.getpid(), signal.SIGTERM)

    def send(self, message):
        self._send_q.put(message)

    def recv(self):
        if self._recv_q.empty():
            return None
        return self._recv_q.get()

    def print_topology_map(self, print_id: bool = False) -> None:
        """Prints out the topology map

        :param print_id: if True, the result includes module id
        :return: None
        """
        self._topology_manager.print_topology_map(print_id)

    @property
    def modules(self) -> Tuple:
        """Tuple of connected modules except network module.
        Example:
        >>> bundle = modi.MODI()
        >>> modules = bundle.modules
        """
        return tuple(self._modules)

    @property
    def buttons(self) -> module_list:
        """Tuple of connected :class:`~modi.module.button.Button` modules.
        """
        return module_list(self._modules, 'button', self.__lazy)

    @property
    def dials(self) -> module_list:
        """Tuple of connected :class:`~modi.module.dial.Dial` modules.
        """
        return module_list(self._modules, "dial", self.__lazy)

    @property
    def displays(self) -> module_list:
        """Tuple of connected :class:`~modi.module.display.Display` modules.
        """
        return module_list(self._modules, "display", self.__lazy)

    @property
    def envs(self) -> module_list:
        """Tuple of connected :class:`~modi.module.env.Env` modules.
        """
        return module_list(self._modules, "env", self.__lazy)

    @property
    def gyros(self) -> module_list:
        """Tuple of connected :class:`~modi.module.gyro.Gyro` modules.
        """
        return module_list(self._modules, "gyro", self.__lazy)

    @property
    def irs(self) -> module_list:
        """Tuple of connected :class:`~modi.module.ir.Ir` modules.
        """
        return module_list(self._modules, "ir", self.__lazy)

    @property
    def leds(self) -> module_list:
        """Tuple of connected :class:`~modi.module.led.Led` modules.
        """
        return module_list(self._modules, "led", self.__lazy)

    @property
    def mics(self) -> module_list:
        """Tuple of connected :class:`~modi.module.mic.Mic` modules.
        """
        return module_list(self._modules, "mic", self.__lazy)

    @property
    def motors(self) -> module_list:
        """Tuple of connected :class:`~modi.module.motor.Motor` modules.
        """
        return module_list(self._modules, "motor", self.__lazy)

    @property
    def speakers(self) -> module_list:
        """Tuple of connected :class:`~modi.module.speaker.Speaker` modules.
        """
        return module_list(self._modules, "speaker", self.__lazy)

    @property
    def ultrasonics(self) -> module_list:
        """Tuple of connected :class:`~modi.module.ultrasonic.Ultrasonic` modules.
        """
        return module_list(self._modules, "ultrasonic", self.__lazy)
Ejemplo n.º 7
0
class MODI:
    def __init__(self,
                 conn_mode: str = "",
                 verbose: bool = False,
                 port: str = None,
                 uuid=""):
        self._modules = list()
        self._topology_data = dict()

        self._conn = self.__init_task(conn_mode, verbose, port, uuid)

        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        print('Start initializing connected MODI modules')
        self._exe_thrd.start()

        self._topology_manager = TopologyManager(self._topology_data,
                                                 self._modules)

        init_time = time.time()
        while not self._topology_manager.is_topology_complete():
            time.sleep(0.1)
            if time.time() - init_time > 5:
                print("MODI init timeout over. "
                      "Check your module connection.")
                break
        check_complete(self)
        print("MODI modules are initialized!")

        bad_modules = (self.__wait_user_code_check()
                       if conn_mode != 'ble' else [])
        if bad_modules:
            cmd = input(f"{[str(module) for module in bad_modules]} "
                        f"has user code in it.\n"
                        f"Reset the user code? [y/n] ")
            if 'y' in cmd:
                self.close()
                modules_to_reset = filter(lambda m: m.is_up_to_date,
                                          bad_modules)
                modules_to_update = filter(lambda m: not m.is_up_to_date,
                                           bad_modules)
                reset_module_firmware(
                    tuple(module.id for module in modules_to_reset))
                update_module_firmware(
                    tuple(module.id for module in modules_to_update))
                self.open()
        atexit.register(self.close)

    def __wait_user_code_check(self):
        def is_not_checked(module):
            return module.user_code_status < 0

        while list(filter(is_not_checked, self._modules)):
            time.sleep(0.1)
        bad_modules = []
        for module in self._modules:
            if module.has_user_code:
                bad_modules.append(module)
        return bad_modules

    # @staticmethod
    # def upload_user_code(filepath: str, remote_path: str) -> None:
    #    """Upload python user code
    #
    #    :param filepath: Filepath to python file
    #    :type filepath: str
    #    :param remote_path: Filepath on esp device
    #    :return: None
    #    """
    #    upload_file(filepath, remote_path)

    @staticmethod
    def __init_task(conn_mode, verbose, port, uuid):
        if not conn_mode:
            is_can = not is_network_module_connected() and is_on_pi()
            conn_mode = 'can' if is_can else 'ser'

        if conn_mode == 'ser':
            return im('modi.task.ser_task').SerTask(verbose, port)
        elif conn_mode == 'can':
            return im('modi.task.can_task').CanTask(verbose)
        elif conn_mode == 'ble':
            mod_path = {
                'win32': 'modi.task.ble_task.ble_task_win',
                'linux': 'modi.task.ble_task.ble_task_rpi',
                'darwin': 'modi.task.ble_task.ble_task_mac',
            }.get(sys.platform)
            return im(mod_path).BleTask(verbose, uuid)
        else:
            raise ValueError(f'Invalid conn mode {conn_mode}')

    def open(self):
        atexit.register(self.close)
        self._exe_thrd = ExeThrd(self._modules, self._topology_data,
                                 self._conn)
        self._conn.open_conn()
        self._exe_thrd.start()

    def close(self):
        atexit.unregister(self.close)
        print("Closing MODI connection...")
        self._exe_thrd.close()
        self._conn.close_conn()

    def send(self, message) -> None:
        """Low level method to send json pkt directly to modules

        :param message: Json packet to send
        :return: None
        """
        self._conn.send_nowait(message)

    def recv(self) -> Optional[str]:
        """Low level method to receive json pkt directly from modules

        :return: Json msg received
        :rtype: str if msg exists, else None
        """
        return self._conn.recv()

    def print_topology_map(self, print_id: bool = False) -> None:
        """Prints out the topology map

        :param print_id: if True, the result includes module id
        :return: None
        """
        self._topology_manager.print_topology_map(print_id)

    @property
    def modules(self) -> module_list:
        """Module List of connected modules except network module.
        """
        return module_list(self._modules)

    @property
    def networks(self) -> module_list:
        return module_list(self._modules, 'network')

    @property
    def buttons(self) -> module_list:
        """Module List of connected Button modules.
        """
        return module_list(self._modules, 'button')

    @property
    def dials(self) -> module_list:
        """Module List of connected Dial modules.
        """
        return module_list(self._modules, "dial")

    @property
    def displays(self) -> module_list:
        """Module List of connected Display modules.
        """
        return module_list(self._modules, "display")

    @property
    def envs(self) -> module_list:
        """Module List of connected Env modules.
        """
        return module_list(self._modules, "env")

    @property
    def gyros(self) -> module_list:
        """Module List of connected Gyro modules.
        """
        return module_list(self._modules, "gyro")

    @property
    def irs(self) -> module_list:
        """Module List of connected Ir modules.
        """
        return module_list(self._modules, "ir")

    @property
    def leds(self) -> module_list:
        """Module List of connected Led modules.
        """
        return module_list(self._modules, "led")

    @property
    def mics(self) -> module_list:
        """Module List of connected Mic modules.
        """
        return module_list(self._modules, "mic")

    @property
    def motors(self) -> module_list:
        """Module List of connected Motor modules.
        """
        return module_list(self._modules, "motor")

    @property
    def speakers(self) -> module_list:
        """Module List of connected Speaker modules.
        """
        return module_list(self._modules, "speaker")

    @property
    def ultrasonics(self) -> module_list:
        """Module List of connected Ultrasonic modules.
        """
        return module_list(self._modules, "ultrasonic")