Exemple #1
0
def convert_awg_pin_to_dio_board(awgPinNumber, configFN = "awg_dio_pin_mapping"):
    """Computes the corresponding board and channel number on the DIO breakout for the
        corresponding input awgPinNumber given the mapping specificed in the configuration
        file provided.
    """
    #First load the mapping config file
    config = load_config(configFN)
    #Get base pin index for board 0,1 and 2,3
    baseB01 = config["B01_base"]
    baseB23 = config["B23_base"]

    currBase = 0
    board = 0

    #Now checking to see which board corresponds with our AWG pin index
    if awgPinNumber >= baseB01 and awgPinNumber < baseB01 + 8:
        #Corresponds with boards 0, 1
        board = 0
        currBase = baseB01
    elif awgPinNumber >= baseB23 and awgPinNumber < baseB23 + 8:
        #Corresponds with boards 2, 3
        board = 2
        currBase = baseB23
    else:
        #Means pin number is not covered by range of those currently connected to the dio
        raise Exception("Invalid pin number")

    #Finally figure out the channel number within the pair of boards
    channel = awgPinNumber-currBase
    if (channel >= 4):
        #If we are beyond channel 4, we are actually on the 2nd board in the pair so update accordingly
        channel = channel - 4
        board = board + 1

    return board, channel
Exemple #2
0
    def save_gui(self,
                 config_filename,
                 folder_root=None,
                 logger=None,
                 scalars=[],
                 labels=[]):
        """ Saves the current GUI state into a config file as a dictionary

        :param config_filename: (str) name of configuration file to save.
            Can be an existing config file with other configuration parameters
        :folder_root: (str) Name of folder where the config files are stored. If None,
        use pylabnet/config
        :logger: (LogClient) instance of LogClient (or LogHandler)
        :param scalars: [str] list of scalar labels to save
        :param labels: [str] list of label labels to save
        """

        # Generate GUI dictionary
        gui_scalars, gui_labels = dict(), dict()
        for scalar in scalars:
            gui_scalars[scalar] = self.get_scalar(scalar)
        for label in labels:
            gui_labels[label] = self.get_text(label)
        data = dict(gui_scalars=gui_scalars, gui_labels=gui_labels)

        # Append to the configuration file if it exists, otherwise create a new one
        filepath = get_config_filepath(config_filename, folder_root)
        if os.path.exists(filepath):
            old_data = load_config(config_filename, folder_root, logger)
        else:
            old_data = dict()
            data = dict(**old_data, **data)
        with open(filepath, 'w') as outfile:
            json.dump(data, outfile, indent=4)
            logger.info(f'Saved GUI data to {filepath}')
Exemple #3
0
    def slack(self, msg_str):
        channel = load_config('slackbot')['logger_channel']
        slackbot = PylabnetSlackBot()
        slackbot.subscribe_channel([channel])

        message = f"Log from `{self._module_tag}`: `{msg_str}`"

        slackbot.broadcast_to_channels(message)
    def check_aom_up(self):
        """Checks if a given HDAWG DIO bit attached to an AOM switch is high"""

        dio_config = load_config('dio_assignment_global')
        DIO_bit = dio_config[self.config["aom_staticline"]]
        current_config = self._hd.geti('dios/0/output')
        DIO_bit_bitshifted = (0b1 << DIO_bit)  # for bit 3: 000...0001000

        DIO_bitup = current_config & DIO_bit_bitshifted

        if DIO_bitup > 0:
            return True
        else:
            return False
    def setup(self):
        ''' Setup a ZI HDAWG driver module to be used as a staticline toggle.

        :DIO_bit: Which bit to toggle, in decimal notation.
        '''

        # Retrieve arguments from keyword argument dictionary.

        assignment_dict = load_config('dio_assignment_global')

        DIO_bit = assignment_dict[self.config['bit_name']]

        # Drive 8-bit bus containing DIO_bit to be toggled.
        # Note that the buses are enabled by using the decimal equivalent
        # of a binary number indicating which bus is driven:
        # 1101 = 11 corresponds to driving bus 1, 2, and 4.

        if DIO_bit in range(8):
            toggle_bit = 1  # 1000
        elif DIO_bit in range(8, 16):
            toggle_bit = 2  # 0100
        elif DIO_bit in range(16, 24):
            toggle_bit = 4  # 0010
        elif DIO_bit in range(24, 32):
            toggle_bit = 8  # 0001
        else:
            self.log.error(
                f"DIO_bit {DIO_bit} invalid, must be in range 0-31.")

        self.DIO_bit = DIO_bit
        self.log.info(
            f"DIO_bit {DIO_bit} successfully assigned to staticline {self.name}."
        )

        # Read in current configuration of DIO-bus.
        current_config = self.hardware_client.geti('dios/0/drive')

        # Set new configuration by using the bitwise OR.
        new_config = current_config | toggle_bit
        self.hardware_client.seti('dios/0/drive', new_config)

        # Register up/down function.
        self.up = lambda: self._HDAWG_toggle(1)
        self.down = lambda: self._HDAWG_toggle(0)

        # Set correct mode to manual
        self.hardware_client.seti('dios/0/mode', 0)
Exemple #6
0
def launch(**kwargs):
    """ Connects to NI-daqMX card and launches server

    :param kwargs: (dict) containing relevant kwargs
        :logger: instance of LogClient for logging purposes
        :port: (int) port number for the Cnt Monitor server
    """

    # Instantiate driver
    ni_daqmx_logger = kwargs['logger']
    try:
        ni_driver = nidaqmx_card.Driver(
            device_name=kwargs['device_id'],
            logger=ni_daqmx_logger
        )
    except AttributeError:
        try:
            config = load_config(kwargs['config'])
            ni_driver = nidaqmx_card.Driver(
                device_name=config['device'],
                logger=ni_daqmx_logger
            )
        except AttributeError:
            ni_daqmx_logger.error('Please provide valid config file')
            raise
        except OSError:
            ni_daqmx_logger.error(f'Did not find NI daqMX name {config["device"]}')
            raise
        except KeyError:
            ni_daqmx_logger.error('No device name provided. '
                                'Please make sure proper config file is provided')
            raise

    # Instantiate server
    ni_daqmx_service = Service()
    ni_daqmx_service.assign_module(module=ni_driver)
    ni_daqmx_service.assign_logger(logger=ni_daqmx_logger)
    ni_daqmx_server = GenericServer(
        service=ni_daqmx_service,
        host=get_ip(),
        port=kwargs['port']
    )

    ni_daqmx_server.start()
Exemple #7
0
    def load_gui(self, config_filename, folder_root=None, logger=None):
        """ Loads and applies GUI settings from a config file

        :param config_filename: (str) name of configuration file to save.
            Can be an existing config file with other configuration parameters
        :folder_root: (str) Name of folder where the config files are stored. If None,
        use pylabnet/config
        :logger: (LogClient) instance of LogClient (or LogHandler)
        """

        data = load_config(config_filename, folder_root, logger)
        if 'gui_scalars' in data:
            for scalar, value in data['gui_scalars'].items():
                self.activate_scalar(scalar)
                self.set_scalar(value, scalar)
                self.deactivate_scalar(scalar)
        if 'gui_labels' in data:
            for label, text in data['gui_labels'].items():
                self.set_label(text, label)
        logger.info(
            f'Loaded GUI values from {get_config_filepath(config_filename, folder_root)}'
        )
Exemple #8
0
    def __init__(self, config=None):

        QMainWindow.__init__(self)

        self.config = load_config(config)
        self.N_staticlines = len(self.config)  #N_staticlines

        self.labels = []

        self.all_widgets = dict()

        self.setStyleSheet("background-color: black;")

        #self.setMinimumSize(QSize(640, 480))
        self.setWindowTitle("Staticline window")

        self.centralWidget = QWidget(self)
        self.setCentralWidget(self.centralWidget)

        self.gridLayout = QGridLayout(self)
        self.centralWidget.setLayout(self.gridLayout)

        self.unpack_config_file()
    def setup(self):
        assignment_dict = load_config('dio_assignment_global')

        DIO_bit = assignment_dict[self.config['bit_name']]
        self.board, self.channel = convert_awg_pin_to_dio_board(DIO_bit)
        self.isHighVoltage = self.config['is_high_volt']
Exemple #10
0
def launch(**kwargs):
    """ Launches the WLM monitor + lock script """

    logger, loghost, logport, clients, guis, params = unpack_launcher(**kwargs)

    hosts = load_config(kwargs['config'], logger=kwargs['logger'])['hosts']

    for host in hosts:

        # Initiate SSH connection
        hostname = f"\'{host['hostname']}\'"
        host_ip = host['ip']

        logger.info(f"Starting SSH connection to {hostname}@{host_ip}")

        ssh = paramiko.SSHClient()
        ssh.load_system_host_keys()

        try:
            ssh.connect(host_ip, username=hostname, password=LOCALHOST_PW)
        except TimeoutError:
            logger.error(f"Failed to setup SSH connection to {hostname}@{host_ip}.")

        logger.info(f"Succesfully connected via SSH to {hostname}@{host_ip}.")

        python_path = host['python_path']
        script_path = host['script_path']
        venv_path =  host['venv_path']
        servers = host['servers']

        # I fappropriate flag is set, kill all python processes on host machine.
        # WARNING: Make sure host machine is not running any non-pylabnet processes.
        if host['kill_all'] == "True":
            logger.warn(f"Killing all python processes on {hostname}@{host_ip}.")
            kill_command = "taskkill /F /IM python.exe /T"
            ssh.exec_command(kill_command)

        for server in servers:

            try:
                disable_raw = server['disable']

                if disable_raw == 'False':
                    disable = False
                else:
                    disable = True
            except KeyError:
                disable = False

            servername = server['servername']
            logger.info(f"Trying to connect to {servername} on {hostname}.")

            # Don't execute any ssh commands if flag is set.
            if disable:
                logger.info(f'Connection to {servername} is disabled')
                continue

            # Look for optional debug flag
            try:
                if server['debug'] == "True":
                    debug = 1
                else:
                    debug = 0
            except KeyError:
                debug = 0

            # Look for optional config flag
            try:
                config = server['config']
            except KeyError:
                config = None

            server_port = np.random.randint(1, 9999)

            # Activate virtual env
            ssh.exec_command(venv_path)

            cmd = '"{}" "{}" --logip {} --logport {} --serverport {} --server {} --debug {} --config {}'.format(
                        python_path,
                        script_path,
                        loghost,
                        logport,
                        server_port,
                        servername,
                        debug,
                        config
                    )
            # Look for device name and ID
            try:
                cmd += f" --device_name {server['device_name']} --device_id {server['device_id']}"
            except KeyError:
                logger.warn(f'Device name and ID not specified for {servername}')
            logger.info(f'Executing command on {hostname}:\n{cmd}')

            ssh.exec_command(cmd)

        ssh.close()
Exemple #11
0
    def start_stop_logging(self, master_log=False):
        """ Starts or stops logging to file depending on situation

        :master_log: (bool) If True, this function is called as initial setup function of
            filesaving for the master launch control. In this case a log path as specified
            in the config file is chosen.
        """

        # check if there's already an open log file and close it
        if self.logfile_date_str is not None:
            self.log_service.stop_latest_logfile()

        if self.main_window.logfile_status_button.isChecked() or master_log:

            date_str = datetime.now().strftime("%Y_%m_%d")
            time_str = datetime.now().strftime("%H_%M_%S")

            # Actually start logging
            filename = f'logfile_{time_str}'

            # Get logging file from json.
            filepath = None
            if master_log:
                try:
                    config_dict = load_config('static_proxy')
                    filepath = config_dict['logger_path']
                except:
                    self.main_window.terminal.setText(
                        'Critical error: '
                        'no logger_path found in static_proxy.json')
                    self.main_window.force_update()
                    time.sleep(10)
                    raise
            # Or from filepath selector.
            else:
                filepath = self.main_window.file_viewer.model().filePath(
                    self.main_window.file_viewer.selectionModel().currentIndex(
                    ))

            try:
                self.log_service.add_logfile(name=filename, dir_path=filepath)
            except Exception as error_msg:
                print(
                    f'Failed to start logging to file {os.path.join(filepath, filename)}.\n{error_msg}'
                )

            self.log_service.logger.info(
                f'Started logging to file {os.path.join(filepath, filename)}.')

            # Change button color and text
            self.main_window.logfile_status_button.setStyleSheet(
                "background-color: red")
            self.main_window.logfile_status_button.setText(
                'Stop logging to file')
            self.main_window.logfile_status_indicator.setChecked(True)

            # Add previous text to logfile
            if self.main_window.log_previous.isChecked():
                self.log_service.logger.info(
                    f'Previous log terminal content: \n{self.main_window.terminal.toPlainText()}'
                    f'\n---------------------------')

            # Pass current date of logfile for day-chopping purposes
            self.logfile_date_str = date_str

            # pass log file name and path to access filesize for chopping purposes
            self.filenamepath = config_dict[
                'logger_path'] + '\\' + date_str[:4] + '\\' + date_str[
                    5:7] + '\\' + date_str[8:] + '\\logfile_' + time_str

        else:

            # Change button color and text
            self.main_window.logfile_status_button.setStyleSheet(
                "background-color: green")
            self.main_window.logfile_status_button.setText(
                'Start logging to file')
            self.main_window.logfile_status_indicator.setChecked(False)

            # Actually stop logging
            self.log_service.stop_latest_logfile()

            # Set date string to None so that logfile does not get updated anymore
            self.logfile_date_str = None
Exemple #12
0
    def __init__(self, proxy=False, master=False, staticproxy=False):
        """ Initializes launch control GUI """

        self.operating_system = get_os()
        self.app = QtWidgets.QApplication(sys.argv)
        self.app.setWindowIcon(
            QtGui.QIcon(
                os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             'devices.ico')))
        # Instantiate GUI application
        if self.operating_system == 'Windows':
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                'pylabnet')

        self.main_window = LaunchWindow(self.app,
                                        self,
                                        gui_template=self.LOGGER_UI)
        self.main_window.stop_button.clicked.connect(self._kill)
        if self.operating_system not in ['Linux', 'Windows']:
            raise UnsupportedOSException
        try:
            if sys.argv[1] == '-m' or master:
                self.master = True
            else:
                self.master = False
        except IndexError:
            if master:
                self.master = True
            else:
                self.master = False

        try:
            if sys.argv[1] == '-p' or proxy:
                self.proxy = True
            else:
                self.proxy = False
        except IndexError:
            if proxy:
                self.proxy = True
            else:
                self.proxy = False

        try:
            if sys.argv[1] == '-sp' or staticproxy:
                self.staticproxy = True
            else:
                self.staticproxy = False
        except IndexError:
            if staticproxy:
                self.staticproxy = True
            else:
                self.staticproxy = False

        self.host = get_ip()
        self.update_index = 0

        # Retrieve static port info.
        if self.master:
            try:
                static_proxy_dict = load_config('static_proxy')
            except:
                print('No config found named static_proxy.json')
                time.sleep(10)
                raise
            self.log_port = static_proxy_dict['master_log_port']
            self.gui_port = static_proxy_dict['master_gui_port']
            hide_console()
        elif self.proxy:
            popup = ParameterPopup(host=str, log_port=str, gui_port=str)
            self.waiting_flag = True
            popup.parameters.connect(self.fill_parameters)
            while self.waiting_flag:
                self.app.processEvents()
        elif self.staticproxy:
            try:
                static_proxy_dict = load_config('static_proxy')
            except:
                print('No config found named static_proxy.json')
                time.sleep(10)
                raise
            self.host = static_proxy_dict['master_ip']
            self.log_port = static_proxy_dict['master_log_port']
            self.gui_port = static_proxy_dict['master_gui_port']
            self.proxy = True
            hide_console()
        else:
            self.log_port = self.LOG_PORT
            self.gui_port = self.GUI_PORT

        self.log_service = None
        self.log_server = None
        self.gui_client = None
        self.gui_logger = None
        self.gui_service = None
        self.gui_server = None
        self.client_list = {}
        self.port_list = {}
        self.script_list = {}
        self.client_data = {}
        self.disconnection = False
        self.debug = False
        self.debug_level = None
        self.autoscroll_off = False
        # date string is None if not logging to file, and gives today's date if logging to file.
        # For day-chopping purposes
        self.logfile_date_str = None
        self.filenamepath = None
        self.MAX_LOG_FILE_SIZE = 5000000  # 5MB
        self.last_seen_buffer = ""

        # setting selection mode for server list to multi-select
        self.main_window.client_list.setSelectionMode(
            QtWidgets.QAbstractItemView.ExtendedSelection)
Exemple #13
0
    def start_gui_server(self):
        """ Starts the launch controller GUI server, or connects to the server and updates GUI"""

        module_str = ''
        if self.proxy:
            module_str = '_proxy'
        # connect to the logger
        try:
            self.gui_logger = LogClient(host=self.host,
                                        port=self.log_port,
                                        module_tag=self.GUI_NAME + module_str,
                                        ui=self.LOGGER_UI)
        except ConnectionRefusedError:
            self.main_window.terminal.setText(
                'Failed to connect to master. Shutting down')
            self.main_window.force_update()
            time.sleep(10)
            raise

        # if lab name is specified: add to gui_logger
        try:
            lab_name_dict = load_config("lab_name")
            lab_name = lab_name_dict['lab_name']
        except:
            lab_name = 'NO_LAB'

        self.gui_logger.update_data(data=dict(lab_name=lab_name))

        # Instantiate GUI server and update GUI with port details
        self.gui_service = Service()
        self.gui_service.assign_module(module=self.main_window)
        self.gui_service.assign_logger(logger=self.gui_logger)
        if self.gui_port is None:
            self.gui_server, self.gui_port = create_server(
                self.gui_service, logger=self.gui_logger, host=get_ip())
            my_port = self.gui_port
            self.main_window.gui_label.setText(f'GUI Port: {my_port}')
        elif self.proxy:
            self.gui_server, my_port = create_server(self.gui_service,
                                                     logger=self.gui_logger,
                                                     host=get_ip())
            self.main_window.gui_label.setText(
                f'Master (Local) GUI Port: {self.gui_port} ({my_port})')
        else:
            try:
                self.gui_server = GenericServer(service=self.gui_service,
                                                host=get_ip(),
                                                port=self.gui_port)
                my_port = self.gui_port
                self.main_window.gui_label.setText(f'GUI Port: {my_port}')
            except ConnectionRefusedError:
                self.gui_logger.error(
                    f'Failed to instantiate GUI Server at port {self.gui_port}'
                )
                raise
        self.gui_server.start()
        self.gui_logger.update_data(data=dict(port=my_port))

        if self.proxy:
            # Connect to the GUI server
            try:
                self.gui_client = Client(host=self.host, port=self.gui_port)
            except ConnectionRefusedError:
                self.gui_logger.error(
                    f'Failed to connect to GUI Server with IP address: {self.host}, '
                    f'Port: {self:gui_port}')
                raise

            # Now update GUI to mirror clients
            self._copy_master()

            # Get the latest update index
            buffer = self.gui_client.get_text('buffer')
            try:
                self.update_index = int(
                    re.findall(r'\d+',
                               re.findall(r'!~\d+~!', buffer)[-1])[0])
            except IndexError:
                self.update_index = 0

            self.gui_service = Service()
            self.gui_service.assign_module(module=self.main_window)
            self.gui_service.assign_logger(logger=self.gui_logger)

        else:

            # Update internal attributes and add to list of log clients
            self.client_list[self.GUI_NAME] = QtWidgets.QListWidgetItem(
                self.GUI_NAME)
            self.port_list[self.GUI_NAME] = [
                port for port in self.log_server._server.clients
            ][0]
            self.main_window.client_list.addItem(
                self.client_list[self.GUI_NAME])
            self.client_list[self.GUI_NAME].setToolTip(
                dict_to_str(self.log_service.client_data[self.GUI_NAME]))
            self.client_data[self.GUI_NAME +
                             module_str] = self.log_service.client_data[
                                 self.GUI_NAME]