Exemplo n.º 1
0
    def refreshModeLabel(self):

        if 'automaticsolver' in self.parameters and self.parameters[
                'automaticsolver']:
            self.modeLabel.setText("<b>%s</b>" % _('AUTO ON'))
        elif 'assistedsolver' in self.parameters and self.parameters[
                'assistedsolver']:
            self.modeLabel.setText("<b>%s</b>" % _('ASSIST ON'))
        else:
            self.modeLabel.setText("<b>%s</b>" % _('MANUAL'))
        self.modeLabel.show()
Exemplo n.º 2
0
 def onStart(self):
     if not os.path.exists(os.path.join('..', 'inpout32.dll')):
         reply = QtWidgets.QMessageBox.question(
             None, _('Error'),
             _("The file '%s' was not found in the current directory. It will not be possible to send trigger events. Do you want to continue?"
               ) % 'inpout32.dll',
             QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
             QtWidgets.QMessageBox.No)
         if reply == QtWidgets.QMessageBox.No:
             self.parent().onEnd()
             return
Exemplo n.º 3
0
    def load_plugins(self):
        """Inform the Main() class with plugins information"""

        # For each plugin that is present in the ./Plugins directory
        for thisfile in os.listdir(PLUGINS_PATH):

            # If it is a python file...
            if thisfile.endswith(".py"):

                # Retrieve the plugin name
                plugin_name = thisfile.replace(".py", "")
                module = SourceFileLoader(plugin_name,
                                          os.path.join(self.working_directory,
                                                       PLUGINS_PATH,
                                                       thisfile)).load_module()

                # module = imp.load_source(plugin_name, os.path.join(self.working_directory, PLUGINS_PATH, thisfile))

                # If the plugin has defined a Task class, log it
                if hasattr(module, "Task"):
                    task = module.Task(self)

                    # Check if a parameters dictionary is present
                    if not hasattr(task, 'parameters'):
                        print(_("Plugin '%s' is invalid (no parameters data)") % (plugin_name))
                        continue

                    # Initialize a dictionary to store plugin information
                    plugin_name = plugin_name.lower()
                    self.PLUGINS_TASK[plugin_name] = {}
                    self.PLUGINS_TASK[plugin_name]['class'] = task
                    self.PLUGINS_TASK[plugin_name]['TIME_SINCE_UPDATE'] = 0
                    self.PLUGINS_TASK[plugin_name]['taskRunning'] = False
                    self.PLUGINS_TASK[plugin_name]['taskPaused'] = False
                    self.PLUGINS_TASK[plugin_name]['taskVisible'] = False

                    # Store potential plugin information
                    if 'taskupdatetime' in task.parameters:
                        self.PLUGINS_TASK[plugin_name]["UPDATE_TIME"] = task.parameters['taskupdatetime']
                    else:
                        self.PLUGINS_TASK[plugin_name]["UPDATE_TIME"] = None

                    if hasattr(task, "keyEvent"):
                        self.PLUGINS_TASK[plugin_name]["RECEIVE_KEY"] = True
                    else:
                        self.PLUGINS_TASK[plugin_name]["RECEIVE_KEY"] = False
                    self.PLUGINS_TASK[plugin_name]["NEED_LOG"] = True if hasattr(task, "onLog") else False

                    task.hide()
                else:
                    print(_("Plugin '%s' is not recognized") % plugin_name)
Exemplo n.º 4
0
    def validateScenario(self, scenario_content):
        """Check that the scenario follows a set of criteria. Output the corresponding boolean value"""

        # Browse the loaded task, ignoring the __main__ one
        for checktask in self.loadedTasks:
            if checktask == "__main__":
                continue

            else:
                howmanyentries = 0
                entries = []
                for k in scenario_content.keys():
                    if checktask in scenario_content[k]:
                        for t in scenario_content[k][checktask]:
                            howmanyentries += 1
                            entries.append(t)

                # Does the scenario contains one or more commands for the task at hand ?
                if howmanyentries == 0:
                    self.showCriticalMessage(_("No entry has been found for the '%s' plugin. Check the scenario file") % checktask )
                    return False

                # Are the start/stop commands present ?
                for thiscommand in ['start']:
                    if thiscommand not in [thisentry[0] for thisentry in entries]:
                        self.showCriticalMessage(_("The '%s' plugin does not admit a %s command. Please fix that") % (checktask, thiscommand))
                        return False

        # Check that the last command of the scenario is an 'end'
        try:
            lasttime, lasttask = [(k, v) for k, v in
                                  sorted(scenario_content.items())][-1]
            lasttask, lastcmd = [(k, v) for k, v in lasttask.items()][-1]

            # Is there more than one task?
            if (len(scenario_content[lasttime].keys()) > 1):
                raise Exception()

            if 'end' not in lastcmd[0]:
                raise Exception()
        except:
            self.showCriticalMessage(_("The scenario should terminate with a 'end' command"))
            return False

        # Check there is at least one task in the scenario
        # Do not take into account the special case of the "__main__" task
        if len(self.loadedTasks) <= 1:
            self.showCriticalMessage(_("No task is started!"))
            return False

        return True
Exemplo n.º 5
0
    def readSample(self):
        res = iViewXAPI.iV_GetSample(byref(sampleData))

        self.samples_to_test.append(res)
        if len(self.samples_to_test
               ) == self.test_window * systemData.samplerate:
            if (float(self.samples_to_test.count(1)) /
                    len(self.samples_to_test)) < 1 - self.sample_threshold:
                self.parent().showCriticalMessage(
                    _("Too many bad samples during the last %s seconds") %
                    +str(self.test_window))
            self.samples_to_test = []

        self.sampleLog.getSmiStamp(sampleData.timestamp)
        self.fromSample = {
            'gazeLX': sampleData.leftEye.gazeX,
            'gazeLY': sampleData.leftEye.gazeY,
            'positionLX': sampleData.leftEye.eyePositionX,
            'positionLY': sampleData.leftEye.eyePositionY,
            'positionLZ': sampleData.leftEye.eyePositionZ,
            'diamL': sampleData.leftEye.diam,
            'gazeRX': sampleData.rightEye.gazeX,
            'gazeRY': sampleData.rightEye.gazeY,
            'positionRX': sampleData.rightEye.eyePositionX,
            'positionRY': sampleData.rightEye.eyePositionY,
            'positionRZ': sampleData.rightEye.eyePositionZ,
            'diamR': sampleData.rightEye.diam
        }

        sample = [
            self.fromSample[entry]
            for entry in self.parameters['getFromSample']
        ]
        self.sampleLog.addLine(sample)
Exemplo n.º 6
0
    def setParameterVariable(self, task, taskclass, variable, value):
        """Set a variable to its value, after having convert it to the correct type"""
        current = getattr(taskclass, PARAMETERS_VARIABLE)

        if not current:
            return False

        command = variable.split("-")

        for e in range(0, len(command) - 1):  # range(0,0) = []
            current = current.get(command[e], None)

        t = type(current[command[-1]])
        if current[command[-1]] is None:
            print(
                _("Warning: None Value in self.parameters. This should not happen!"
                  ))

        # Must test booleen first because booleen are also int (e.g., True == 1 is True)
        if isinstance(current[command[-1]], bool):
            if value.lower() == 'true':
                current[command[-1]] = True
            elif value.lower() == 'false':
                current[command[-1]] = False
        elif isinstance(current[command[-1]], int):
            current[command[-1]] = int(value)
        elif isinstance(current[command[-1]], float):
            current[command[-1]] = float(value)
        elif isinstance(current[command[-1]],
                        str) or current[command[-1]] is None:
            current[command[-1]] = value
        else:
            try:
                current[command[-1]] = ast.literal_eval(value)
            except:
                self.showCriticalMessage(
                    _("Unable to evaluate a value! This should not happen!"))

        # Retrieve changing value that are handled by MATB.py (e.g., title, taskupdatetime)
        if variable == 'title':
            self.PLUGINS_TASK[task]['ui_label'].setText(value)
        elif variable == 'taskupdatetime' and isinstance(
                current[command[-1]], int):
            self.PLUGINS_TASK[task]['UPDATE_TIME'] = int(value)
Exemplo n.º 7
0
    def onStart(self):

        # Define a QLabel object to potentially display automation mode
        self.modeFont = QtGui.QFont("sans-serif", int(self.height() / 35.),
                                    QtGui.QFont.Bold)
        self.modeLabel = QtWidgets.QLabel(self)
        self.modeLabel.setGeometry(
            QtCore.QRect(0.60 * self.width(), 0.60 * self.height(),
                         0.40 * self.width(), 0.40 * self.height()))
        self.modeLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.modeLabel.setFont(self.modeFont)

        self.parameters['displaytitle'] = True

        # Set a WTrack Qt object
        self.widget = WTrack.WTrack(self, self.parameters['equalproportions'])

        # Create a layout for the widget
        layout = QtWidgets.QGridLayout()

        # Add the WTrack object to the layout
        layout.addWidget(self.widget)
        self.setLayout(layout)

        pygame.joystick.init()

        # Check for a joystick device
        if pygame.joystick.get_count() == 0:
            self.parent().showCriticalMessage(
                _("Please plug a joystick for the '%s' task!") %
                (self.parameters['title']))
        else:
            self.my_joystick = pygame.joystick.Joystick(0)
            self.my_joystick.init()

        # Log some task information once
        self.buildLog(["STATE", "TARGET", "X", str(0.5)])
        self.buildLog(["STATE", "TARGET", "Y", str(0.5)])
        self.buildLog([
            "STATE", "TARGET", "RADIUS",
            str(self.parameters['targetradius'])
        ])
        msg = _('AUTO') if self.parameters['automaticsolver'] else _('MANUAL')
        self.buildLog(["STATE", "", "MODE", msg])
Exemplo n.º 8
0
    def onUpdate(self):

        if self.parameters['displayautomationstate']:
            self.refreshModeLabel()
        else:
            self.modeLabel.hide()
        
        if self.parameters['resetperformance'] is not None:
            if self.parameters['resetperformance'] in ['last', 'global']:
                for this_index in self.performance[self.parameters['resetperformance']]:
                    self.performance[self.parameters['resetperformance']][this_index] = 0
            else:
                self.parent().showCriticalMessage(_("%s : wrong argument in sysmon;resetperformance") % self.parameters['resetperformance'])
            self.parameters['resetperformance'] = None
            
        # For each light button, refresh name
        for index, k in enumerate(self.parameters['lights'].keys()):
            self.parameters['lights'][k]['ui'].light.setText(self.parameters['lights'][k]['name'])

        # For each scale gauge, refresh name
        for k in sorted(self.parameters['scales'].keys()):
            self.parameters['scales'][k]['ui'].label.setText(self.parameters['scales'][k]['name'])


        # 1. Check failures only if no failure is already occuring
        # (currently prevents double-failure !)
        if len(self.currentFailure) == 0:
            for lights_or_scales in ['lights', 'scales']:
                for thisGauge in self.parameters[lights_or_scales].keys():

                    # If a failure is to be initiated
                    if (lights_or_scales == 'scales' and self.parameters[lights_or_scales][thisGauge]['failure'] in ['up', 'down']) or (lights_or_scales == 'lights' and self.parameters[lights_or_scales][thisGauge]['failure']):

                        # Start it...
                        self.startFailure(lights_or_scales, thisGauge)
                        # ...and leave the loop
                        break

        # 2. Vary position of each scale, depending on its state (up, down, no)
        for thisScale in self.parameters['scales'].keys():
            self.parameters['scales'][thisScale][
                'position'] = self.computeNextPosition(thisScale)

        # 3. Refresh visual display
        for thisScale in self.parameters['scales'].keys():
            if 'ui' in self.parameters['scales'][thisScale]:
                self.parameters['scales'][thisScale][
                    'ui'].style = self.parameters['scalestyle']
                self.parameters['scales'][thisScale][
                    'ui'].position = self.parameters['scales'][thisScale]['position']

        for thisLight in self.parameters['lights'].keys():
            if 'ui' in self.parameters['lights'][thisLight]:
                self.parameters['lights'][thisLight]['ui'].refreshState(
                    self.parameters['lights'][thisLight]['on'])
Exemplo n.º 9
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        # SCHEDULING PARAMETERS ###
        self.parameters = {
            'title': 'Scheduling',
            'taskplacement': "topright",
            'taskupdatetime': 1000
        }

        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])
Exemplo n.º 10
0
    def showCriticalMessage(self, msg):
        """Display a critical message (msg) in a QMessageBox Qt object before exiting"""

        flags = QtWidgets.QMessageBox.Abort
        flags |= QtWidgets.QMessageBox.StandardButton.Ignore

        result = QtWidgets.QMessageBox.critical(
            self, VERSIONTITLE + " " + _("Error"), msg, flags)

        if result == QtWidgets.QMessageBox.Abort:
            self.onEnd()
            sys.exit()
Exemplo n.º 11
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        # COMMUNICATIONS PARAMETERS ###
        self.parameters = {
            'title': 'Communications',
            'taskplacement': "bottomleft",
            'taskupdatetime': 50,
            'callsignregex': '[A-Z][A-Z][A-Z]\d\d\d',
            'owncallsign': '',
            'othercallsign': [],
            'othercallsignnumber': 5,
            'airbandminMhz': 108,
            'airbandmaxMhz': 137,
            'airbandminvariationMhz': 5,
            'airbandmaxvariationMhz': 6,
            'radiostepMhz': 0.1,
            'voicegender': 'male',
            'voiceidiom': 'french',
            'radioprompt': '',
            'promptlist': ['NAV_1', 'NAV_2', 'COM_1', 'COM_2'],
            'automaticsolver': False,
            'displayautomationstate': False,
        }

        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])

        # Preallocate a dictionary to handle radios information
        self.parameters['radios'] = {}
        for this_destination in ['own', 'other']:
            self.parameters['radios'][this_destination] = {}
            for r, this_radio in enumerate(self.parameters['promptlist']):
                self.parameters['radios'][this_destination][r] = {
                    'name': this_radio,
                    'currentfreq': None,
                    'targetfreq': None,
                    'lasttarget': None,
                    'index': r
                }

        self.parameters['frequencyresolutionKhz'] = 100

        # Use list to learn about already created callsign/radio... to minimize
        # repetitions
        self.letters = string.ascii_uppercase
        self.digits = string.digits
        self.lastradioselected = ''

        # Set a boolean to handle automatic solving
        self.automaticsolving = False
Exemplo n.º 12
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        # RESMAN PARAMETERS ###
        self.parameters = {
            'taskplacement': 'bottommid',
            'taskupdatetime': 2000,
            'title': 'Resources management',
            'heuristicsolver': False,
            'assistedsolver': False,
            'displayautomationstate': False,
            'pumpcoloroff' : '#AAAAAA',
            'pumpcoloron' : '#00FF00',
            'pumpcolorfailure' : '#FF0000',
            'tolerancelevel':500,
            'displaytolerance':True,
            'resetperformance':None,

            'pump': {'1': {'flow': 800, 'state': 0, 'keys': [QtCore.Qt.Key_1], 'hide': 0},
                     '2': {'flow': 600, 'state': 0, 'keys': [QtCore.Qt.Key_2, 233], 'hide': 0},
                     '3': {'flow': 800, 'state': 0, 'keys': [QtCore.Qt.Key_3], 'hide': 0},
                     '4': {'flow': 600, 'state': 0, 'keys': [QtCore.Qt.Key_4],'hide': 0},
                     '5': {'flow': 600, 'state': 0, 'keys': [QtCore.Qt.Key_5], 'hide': 0},
                     '6': {'flow': 600, 'state': 0, 'keys': [QtCore.Qt.Key_6], 'hide': 0},
                     '7': {'flow': 400, 'state': 0, 'keys': [QtCore.Qt.Key_7, 232], 'hide': 0},
                     '8': {'flow': 400, 'state': 0, 'keys': [QtCore.Qt.Key_8], 'hide': 0}},

            'tank': {
                'a': {'level': 2500, 'max': 4000, 'target': 2500, 'depletable': 1, 'lossperminute': 800, 'hide': 0},
                'b': {'level': 2500, 'max': 4000, 'target': 2500, 'depletable': 1, 'lossperminute': 800, 'hide': 0},
                'c': {'level': 1000, 'max': 2000, 'target': None, 'depletable': 1, 'lossperminute': 0, 'hide': 0},
                'd': {'level': 1000, 'max': 2000, 'target': None, 'depletable': 1, 'lossperminute': 0, 'hide': 0},
                'e': {'level': 3000, 'max': 4000, 'target': None, 'depletable': 0, 'lossperminute': 0, 'hide': 0},
                'f': {'level': 3000, 'max': 4000, 'target': None, 'depletable': 0, 'lossperminute': 0, 'hide': 0}
            }
        }
        
        self.performance = {
            'total' : {},
            'last'  : {}
        }
        
        for this_cat in self.performance:
            for this_tank in self.parameters['tank']:
                if self.parameters['tank'][this_tank]['target'] is not None:
                    self.performance[this_cat][this_tank+'_in'] = 0
                    self.performance[this_cat][this_tank+'_out'] = 0
        
        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])
Exemplo n.º 13
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        self.resman = None

        # PUMPSTATUS PARAMETERS ###
        self.parameters = {
            'taskplacement': 'bottomright',
            'taskupdatetime': 1000,
            'title': 'Pump status'
        }

        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])
Exemplo n.º 14
0
    def scenarioUpdateTime(self):
        """Increment time (h,m,s) and get the corresponding string chain (H:MM:SS)"""
        m, s = divmod(self.totalElapsedTime_ms / 1000.0, 60)
        h, m = divmod(m, 60)

        if h > 9:
            self.showCriticalMessage(_("Timing overflow. This should not happen!"))

        s = "%d:%02d:%02d" % (h, m, s)

        # If scenarioTimeStr need to be updated (1 second passed), update it
        # and try to execute scenario contents again (see the executeScenario fucntion above)
        if s != self.scenarioTimeStr:
            self.scenarioTimeStr = s
            self.executeScenario(self.scenarioTimeStr)
Exemplo n.º 15
0
    def scheduler(self):
        """Manage the passage of time. Block time during pauses"""
        current_time_microsec = self.default_timer()
        elapsed_time_ms = (current_time_microsec -
                           self.last_time_microsec) * 1000.0

        if elapsed_time_ms < MAIN_SCHEDULER_INTERVAL:
            return

        self.last_time_microsec = current_time_microsec

        # The main experiment is in pause, so do not increment time
        if self.experiment_pause or not self.experiment_running:
            return

        # Time increment in case the experiment is running
        self.totalElapsedTime_ms += elapsed_time_ms

        # If experiment is effectively running, browse plugins and refresh them (execute their onUpdate() method) as a function of their own UPDATE_TIME
        for plugin_name in self.PLUGINS_TASK:
            if plugin_name in self.loadedTasks:
                if self.PLUGINS_TASK[plugin_name][
                        "UPDATE_TIME"] is not None and not self.PLUGINS_TASK[
                            plugin_name]['taskPaused']:
                    self.PLUGINS_TASK[plugin_name][
                        "TIME_SINCE_UPDATE"] += elapsed_time_ms
                    if self.PLUGINS_TASK[plugin_name][
                            "TIME_SINCE_UPDATE"] >= self.PLUGINS_TASK[
                                plugin_name]["UPDATE_TIME"]:
                        self.PLUGINS_TASK[plugin_name]["TIME_SINCE_UPDATE"] = 0
                        if hasattr(self.PLUGINS_TASK[plugin_name]["class"],
                                   "onUpdate"):
                            self.PLUGINS_TASK[plugin_name]["class"].onUpdate()
                        else:
                            self.showCriticalMessage(
                                _("Plugin '%s' requires an onUpdate() function!"
                                  ) % plugin_name)

        # Potentially logs an arbitrary message in 'messagetolog'
        if len(self.parameters['messagetolog']) > 0:
            msg = ["MAIN", "LOG", self.parameters['messagetolog']]
            self.mainLog.addLine(msg)
            self.parameters['messagetolog'] = ''

        self.scenarioUpdateTime()
Exemplo n.º 16
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        self.my_joystick = None

        # TRACK PARAMETERS ###
        self.parameters = {
            'taskplacement': 'topmid',
            'taskupdatetime': 20,
            'title': 'Tracking',
            'cursorcolor': '#0000FF',
            'cursorcoloroutside': '#0000FF',
            'automaticsolver': False,
            'displayautomationstate': True,
            'assistedsolver': False,
            'targetradius': 0.1,
            'joystickforce': 1.0,
            'cutofffrequency': 0.06,
            'equalproportions': True,
            'resetperformance': None,
        }

        self.performance = {
            'total': {
                'time_in_ms': 0,
                'time_out_ms': 0,
                'points_number': 0,
                'deviation_mean': 0
            },
            'last': {
                'time_in_ms': 0,
                'time_out_ms': 0,
                'points_number': 0,
                'deviation_mean': 0
            }
        }

        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])
Exemplo n.º 17
0
    def onStart(self):

        # Retrieve scenario events for the tracking and the communication tasks
        self.tracking_schedule, self.communication_schedule = self.getSchedule(
        )

        # Get the time of the last event
        maxTime_sec = max([
            self.dateStringToSecondInteger(this_time)
            for this_time, value in self.parent().scenariocontents.items()
        ])

        # Set a Qt layout
        layout = QtWidgets.QGridLayout()

        # Set a WScheduler Qt object
        self.widget = WScheduler.WScheduler(self, self.tracking_schedule,
                                            self.communication_schedule,
                                            maxTime_sec, _('Elapsed Time'))
        layout.addWidget(self.widget)
        self.setLayout(layout)

        # Compute tasks progression as a function of current scenario time
        self.widget.getProgression(self.parent().scenarioTimeStr)
Exemplo n.º 18
0
    def __init__(self, scenario_fullpath):
        super(Main, self).__init__(parent=None)
        self.registeredTaskTimer = []
        self.parameters = {
            'showlabels': True,
            'allowescape': True,
            'messagetolog': ''
        }

        # Preallocate a dictionary to store plugins information
        self.PLUGINS_TASK = {}

        # Store working directory and scenario names
        # Use correct directory if running in cxFreeze (frozen)
        if getattr(sys, 'frozen', False):
            self.working_directory = os.getcwd()
        else:
            self.working_directory = os.path.dirname(os.path.abspath(__file__))

        self.scenario_shortfilename = os.path.split(scenario_fullpath)[1]
        self.scenario_directory = os.path.split(scenario_fullpath)[0]
        self.scales_directory = os.path.join(self.working_directory, SCALES_PATH)
        self.instructions_directory = os.path.join(self.working_directory, INSTRUCTIONS_PATH)

        # Check that the plugins folder exists
        if not os.path.exists(os.path.join(self.working_directory, PLUGINS_PATH)):
            self.showCriticalMessage(
                _("Plugins directory does not exist. Check that its name is correct"))

        # Create a ./Logs folder if it does not exist
        if not os.path.exists(os.path.join(self.working_directory, LOGS_PATH)):
            os.mkdir(os.path.join(self.working_directory, LOGS_PATH))

        # Create a filename for the log file
        # Corresponds to : scenario name + date + .log
        LOG_FILE_NAME = os.path.join(self.scenario_shortfilename.replace(".txt", "").replace(
            " ", "_") + "_" + datetime.datetime.now().strftime("%Y%m%d_%H%M") + ".log")
        self.LOG_FILE_PATH = os.path.join(self.working_directory, LOGS_PATH, LOG_FILE_NAME)

        # Initialize a Logger instance with this log filename (see Helpers/Logger.py)
        self.mainLog = Logger.Logger(self, self.LOG_FILE_PATH)
        self.mainLog.addLine(['MAIN', 'INFO', 'SCENARIO', 'FILENAME', self.scenario_shortfilename])

        # Initialize two timing variables
        self.scenarioTimeStr = None
        self.totalElapsedTime_ms = 0

        # Compute screen dimensions
        # Screen index can be changed just below

        screen_idx = 0  # Here, you can change the screen index
        screen = QtGui.QGuiApplication.screens()[screen_idx]
        self.screen_width = screen.geometry().width()
        self.screen_height = screen.geometry().height()

        # screen_widths = [QtWidgets.QApplication.desktop().screenGeometry(i).width() for i in range(0, QtWidgets.QApplication.desktop().screenCount())]
        #
        # self.screen_index = screen_widths.index(self.screen_width)
        #     self.screen_index).height()
        #
        # # Get current screen
        # current_screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
        #centerPoint = QtWidgets.QApplication.desktop().screenGeometry(current_screen).center()
        #self.move(centerPoint)

        self.setFixedSize(self.screen_width, self.screen_height)

        # Log the computed screen size values
        self.mainLog.addLine(
            ['MAIN', 'INFO', 'SCREENSIZE', 'WIDTH', str(self.screen_width)])
        self.mainLog.addLine(
            ['MAIN', 'INFO', 'SCREENSIZE', 'HEIGHT', str(self.screen_height)])

        #  The following dictionary contains all the information about sizes and placements.
        #  control_top/left is the top/left margin
        #  control_height/width defines the plugin height/width
        self.placements = {
            'fullscreen': {'control_top': 0, 'control_left': 0, 'control_height': self.screen_height,
                           'control_width': self.screen_width},

            'topleft': {'control_top': 0, 'control_left': 0, 'control_height': self.screen_height / 2,
                        'control_width': self.screen_width * (7.0 / 20.1)},

            'topmid': {'control_top': 0, 'control_left': self.screen_width * (
                    5.9 / 20.1), 'control_height': self.screen_height / 2,
                       'control_width': self.screen_width * (10.7 / 20.1)},

            'topright': {'control_top': 0, 'control_left': self.screen_width * (5.9 / 20.1) + self.screen_width * (
                    10.6 / 20.1), 'control_height': self.screen_height / 2,
                         'control_width': self.screen_width * (3.6 / 20.1)},

            'bottomleft': {'control_top': self.screen_height / 2, 'control_left': 0, 'control_height':
                self.screen_height / 2, 'control_width': self.screen_width * (5.9 / 20.1)},

            'bottommid': {'control_top': self.screen_height / 2, 'control_left': self.screen_width * (
                    5.9 / 20.1), 'control_height': self.screen_height / 2,
                          'control_width': self.screen_width * (10.7 / 20.1)},

            'bottomright': {'control_top': self.screen_height / 2, 'control_left': self.screen_width * (5.9 / 20.1) +
                                                                                   self.screen_width * (10.6 / 20.1),
                            'control_height': self.screen_height / 2,
                            'control_width': self.screen_width * (3.6 / 20.1)}
        }

        # Turn off Caps Lock and on Num Lock (for resman)... if possible (only Windows until now)
        if platform.system() == "Windows":
            self.turnKey(0x14, False)  # Caps Lock Off
            self.turnKey(0x90, True)  # Num Lock On

        # Preallocate variables to handle experiment pauses
        self.experiment_pause = False
        self.experiment_running = True

        # Initialize plugins
        self.load_plugins()
        self.place_plugins_on_screen()
        self.loadedTasks = []

        # Load scenario file
        self.scenariocontents = self.loadScenario(scenario_fullpath)
Exemplo n.º 19
0
    def getCommand(self, lineNumber, lineContent):
        """Parse lineContent to time, task and command variables.
            There are 3 possible syntax:
            0:00:00;end => call onEnd in main script
            0:00:00;track;start => call onStart in the track plugins
            0:00:00;track;variable;value=> modify the parameters in the track plugins
         """

        # Retrieve line content, removing white space and using semi-colon as delimiter
        lineList = lineContent.strip().split(';')

        # Check if the length of lineList is correct
        if not 1 < len(lineList) < 5:
            self.showCriticalMessage(_("Error. Number of value is incorrect. See line")+" " + str(lineNumber) + ' (' + str(lineContent) + ')')
            return None, None, None

        # Manage the special case of main (0:00:00;start)
        elif len(lineList) == 2 or lineList[1] in self.parameters.keys():
            lineList.insert(1, "__main__")
        time, task, command = lineList[0], lineList[1], lineList[2:]

        # manage deprecated command:
        if task=="sysmon" and command[0]=="feedbackduration":
            command[0] = "feedbacks-positive-duration"

        if task == "__main__":
            taskclass = self
        elif task in self.PLUGINS_TASK:
            taskclass = self.getPluginClass(task)
        else:
            self.showCriticalMessage(
                _("'%s' plugin: unknown\n\nLINE: %s") % (task, str(lineNumber)))
            return None, None, None

        if len(time)!=7:
            self.showCriticalMessage(
                _("'%s' plugin: wrong time format\n\nLINE: %s") % (task, str(lineNumber)))

        # When only one command, concatenate it with the 'on' chain (e.g. start leads to onStart)
        # onCommand functions are called into the plugins
        if len(command) == 1:
            functionname = "on" + command[0].capitalize()

            # If the onCommand does not exist...
            if not hasattr(taskclass, functionname) and functionname not in ["onStart", "onStop", "onHide", "onPause", "onShow", "onResume"]:

                # signal it.
                errorcaller = ""
                if task != "__main__":
                    errorcaller = "' in '" + task

                self.showCriticalMessage(
                    _("'%s' not found!\n\nLINE: %s") % (functionname + errorcaller, str(lineNumber)))
                return None, None, None
            else:
                return time, task, command

        # For the other variables, check that there are corrects (available in the plugin)
        else:
            # if taskclass == self:
            #     self.showCriticalMessage(
            #         _("The main script parameters should not be called, use a task instead!\n\nLINE: %s") % str(lineNumber))
            #     return None, None, None

            if not hasattr(taskclass, PARAMETERS_VARIABLE):
                self.showCriticalMessage(
                    _("'%s' should have a parameters dictionary!\n\nLINE: %s") % (task, str(lineNumber)))
                return None, None, None

            if not self.testParameterVariable(task, taskclass, command[0]):
                self.showCriticalMessage(
                    _("Variable '%s' unknown in task '%s'\n\nLINE: %s") % (str(command [0]), task, str(lineNumber)))
                return None, None, None

        return time, task, command
Exemplo n.º 20
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        # SYSMON PARAMETERS ###
        self.parameters = {
            'title': 'System monitoring',
            'taskplacement': 'topleft',
            'taskupdatetime': 200,
            'alerttimeout': 10000,
            'automaticsolver': False,
            'automaticsolverdelay': 1 * 1000,
            'displayautomationstate': False,
            'allowanykey': False,
            'scalesnumofboxes': 11,
            'safezonelength': 3,
            'feedback' : True,
            'feedbackduration': 1.5 * 1000,
            'scalestyle' : 1, # could be defined at the scale level
            'resetperformance':None,

            'lights': {
                '1': {'name': 'F5', 'failure': False, 'on': True, 'default': 'on', 'oncolor': "#009900", 'keys': [QtCore.Qt.Key_F5]},
                '2': {'name': 'F6', 'failure': False, 'on': False, 'default': 'off', 'oncolor': "#FF0000", 'keys': [QtCore.Qt.Key_F6]}
            },

            'scales': {
                '1': {'name': 'F1', 'failure': 'no', 'keys': [QtCore.Qt.Key_F1]},
                '2': {'name': 'F2', 'failure': 'no', 'keys': [QtCore.Qt.Key_F2]},
                '3': {'name': 'F3', 'failure': 'no', 'keys': [QtCore.Qt.Key_F3]},
                '4': {'name': 'F4', 'failure': 'no', 'keys': [QtCore.Qt.Key_F4]}
            }
            }
            
        self.performance = {
            'total' : {'hit_number': 0, 'miss_number':0, 'fa_number':0},
            'last'  : {'hit_number': 0, 'miss_number':0, 'fa_number':0}
        }
            
        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])

        # Set the initial position of the cursor (middle)
        for this_scale in self.parameters['scales'].keys():
            self.parameters['scales'][this_scale][
                'position'] = self.parameters['scalesnumofboxes'] / 2

        # Define two failures zones (up, down)
        totalRange = range(1, self.parameters['scalesnumofboxes'] - 1)
        centerPosition = totalRange[len(totalRange) / 2]
        self.zones = {
            'up': [k for k in totalRange if k < (centerPosition - (self.parameters['safezonelength'] - 1) / 2)],
            'down': [k for k in totalRange if k > (centerPosition + (self.parameters['safezonelength'] - 1) / 2)]
        }

        # Define the "safe" zone (no)
        self.zones['no'] = [k for k in totalRange if k not in self.zones['up'] if k not in self.zones['down']]

        # Set a list of accepted keys depending on lights and scales parameters
        scales_keys = [self.parameters['scales'][id]["keys"][0]
                       for id in self.parameters['scales'].keys()]
        lights_keys = [self.parameters['lights'][id]["keys"][0]
                       for id in self.parameters['lights'].keys()]
        self.accepted_keys = scales_keys + lights_keys
Exemplo n.º 21
0
    def place_plugins_on_screen(self):
        """Compute size and position of each plugin, in a 2 x 3 canvas,
        as a function of the taskplacement variable of each plugin"""

        # Compute some sizes as a function of screen height
        LABEL_HEIGHT = self.screen_height / 27
        font_size_pt = int(LABEL_HEIGHT / (5 / 2))

        # Adapt top margin and height to the presence/absence of plugin labels
        if self.parameters['showlabels']:
            for k in self.placements.keys():
                self.placements[k]['control_top'] += LABEL_HEIGHT
                self.placements[k]['control_height'] -= LABEL_HEIGHT

        # Browse plugins to effectively size and place them
        for plugin_name in self.PLUGINS_TASK:
            plugin = self.getPluginClass(plugin_name)

            # Check if the plugin has a taskplacement parameter
            if 'taskplacement' not in plugin.parameters or not plugin.parameters['taskplacement']:
                print(_("Plugin '%s' has no placement data. It will not be displayed") % plugin_name)
                continue

            # If so, retrieve it
            placement = plugin.parameters['taskplacement']

            # Plugin placement must match one value of the self.placement dictionary
            if placement in self.placements.keys():
                self.control_top = self.placements[placement]['control_top']
                self.control_left = self.placements[placement]['control_left']
                self.control_height = self.placements[
                    placement]['control_height']
                self.control_width = self.placements[
                    placement]['control_width']

                # If the plugin is not displayed in fullscreen, log information about its area of interest (AOI)
                if placement != 'fullscreen':
                    thisPlacement = self.placements[placement]
                    AOIx = [int(thisPlacement['control_left']), int(
                        thisPlacement['control_left'] + thisPlacement['control_width'])]
                    AOIy = [int(thisPlacement['control_top']), int(
                        thisPlacement['control_top'] + thisPlacement['control_height'])]

                    self.mainLog.addLine(
                        ['MAIN', 'INFO', plugin_name.upper(), 'AOI_X', AOIx])
                    self.mainLog.addLine(
                        ['MAIN', 'INFO', plugin_name.upper(), 'AOI_Y', AOIy])

                    # For each non-fullscreen plugin, show its label if needed
                    if self.parameters['showlabels']:
                        self.PLUGINS_TASK[plugin_name]['ui_label'] = QtWidgets.QLabel(self)
                        self.PLUGINS_TASK[plugin_name]['ui_label'].setStyleSheet("font: " + str(font_size_pt) + "pt \"MS Shell Dlg 2\"; background-color: black; color: white;")
                        self.PLUGINS_TASK[plugin_name]['ui_label'].setAlignment(QtCore.Qt.AlignCenter)
                        self.PLUGINS_TASK[plugin_name]['ui_label'].resize(self.control_width, LABEL_HEIGHT)
                        self.PLUGINS_TASK[plugin_name]['ui_label'].move(self.control_left, self.control_top - LABEL_HEIGHT)

            else:
                self.showCriticalMessage(
                    _("Placement '%s' is not recognized!") % placement)

            # Resize, place and show the plugin itself
            plugin.resize(self.control_width, self.control_height)
            plugin.move(self.control_left, self.control_top)
            plugin.show()
Exemplo n.º 22
0
    def onUpdate(self):

        if self.parameters['displayautomationstate']:
            self.refreshModeLabel()
        else:
            self.modeLabel.hide()

        if self.parameters['resetperformance'] is not None:
            if self.parameters['resetperformance'] in ['last', 'global']:
                for i in self.performance[self.parameters['resetperformance']]:
                    self.performance[
                        self.parameters['resetperformance']][i] = 0
            else:
                self.parent().showCriticalMessage(
                    _("%s : wrong argument in track;resetperformance") %
                    self.parameters['resetperformance'])
            self.parameters['resetperformance'] = None

        # Preallocate x and y input variables
        x_input, y_input = 0, 0

        # Compute next cursor coordinates (x,y)
        current_X, current_Y = self.widget.moveCursor()

        # If automatic solver : always correct cursor position
        if self.parameters['automaticsolver']:
            x_input, y_input = self.widget.getAutoCompensation()

        # Else record manual compensatory movements
        else:
            # Retrieve potentials joystick inputs (x,y)
            x_input, y_input = self.joystick_input()

            # If assisted solver : correct cursor position only if joystick
            # inputs something
            if self.parameters['assistedsolver']:
                if any([this_input != 0 for this_input in [x_input, y_input]]):
                    x_input, y_input = self.widget.getAutoCompensation()

        # Modulate cursor position with potentials joystick inputs
        current_X += x_input
        current_Y += y_input

        # Refresh the display
        self.widget.refreshCursorPosition(current_X, current_Y)

        # Constantly log the cursor coordinates
        self.buildLog(["STATE", "CURSOR", "X", str(current_X)])
        self.buildLog(["STATE", "CURSOR", "Y", str(current_Y)])

        # Record performance
        for perf_cat, perf_val in self.performance.items():
            if self.widget.isCursorInTarget():
                perf_val['time_in_ms'] += self.parameters['taskupdatetime']
            else:
                perf_val['time_out_ms'] += self.parameters['taskupdatetime']

            current_deviation = self.widget.returnAbsoluteDeviation()
            perf_val['points_number'] += 1
            perf_val['deviation_mean'] = perf_val['deviation_mean'] * (
                (perf_val['points_number'] - 1) /
                float(perf_val['points_number'])) + current_deviation * (
                    float(1) / perf_val['points_number'])
Exemplo n.º 23
0
    else:
        print("{}:{}".format(_(title),_(msg)))
    sys.exit()


# Ensure that Pyside2, pygame, rstr, psutil and wave are available
try:
    from PySide2 import QtCore, QtWidgets, QtGui
    #we need to hide pygame message in order to precisely control the output log
    os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
    import pygame
    import rstr
    import psutil
    import wave
except Exception as e:
    OSCriticalErrorMessage(_("Error"),
        _("Please check that all required libraries are installed:\n\n"+str(e)))


class Main(QtWidgets.QMainWindow):

    def __init__(self, scenario_fullpath):
        super(Main, self).__init__(parent=None)
        self.registeredTaskTimer = []
        self.parameters = {
            'showlabels': True,
            'allowescape': True,
            'messagetolog': ''
        }

        # Preallocate a dictionary to store plugins information
Exemplo n.º 24
0
    def onStart(self):
        # Prepare a dict for each task that records performance
        for this_plugin in self.parent().PLUGINS_TASK:
            if hasattr(self.parent().PLUGINS_TASK[this_plugin]['class'],
                       'performance'):
                self.performances[this_plugin] = dict()

        # Retrieve performance values since last feedback, store it in a dict
        for this_plugin in self.performances:
            self.performances[this_plugin]['infos'] = self.parent(
            ).PLUGINS_TASK[this_plugin]['class'].performance

            # Prepare text object
            what_location = self.parent(
            ).PLUGINS_TASK[this_plugin]['class'].parameters['taskplacement']
            placement = self.parent().placements[what_location]
            self.performances[this_plugin]['uis'] = dict()
            self.performances[this_plugin]['uis'][
                'perf_label'] = QtWidgets.QLabel(self)
            self.performances[this_plugin]['uis']['perf_label'].setGeometry(
                QtCore.QRect(placement['control_left'],
                             placement['control_top'],
                             placement['control_width'],
                             placement['control_height']))
            self.performances[this_plugin]['uis']['perf_label'].setAlignment(
                QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)
            self.performances[this_plugin]['uis']['perf_label'].setFont(
                self.mainFont)

            text = str()
            if this_plugin == 'resman':
                for this_tank in ['a', 'b']:
                    perf = round(
                        self.performances[this_plugin]['infos']['last'][
                            this_tank + '_in'] /
                        (self.performances[this_plugin]['infos']['last'][
                            this_tank + '_in'] + self.performances[this_plugin]
                         ['infos']['last'][this_tank + '_out']) *
                        100, 1) if (self.performances[this_plugin]['infos']
                                    ['last'][this_tank + '_in'] +
                                    self.performances[this_plugin]['infos']
                                    ['last'][this_tank + '_out']) != 0 else 100
                    this_text = _(
                        "%s tank: on average, you have maintained this tank at a correct level %s%% of time"
                    ) % (this_tank.upper(), perf)
                    text += this_text + '\r\n'
                self.performances[this_plugin]['uis'][
                    'perf_label'].setWordWrap(1)
                self.performances[this_plugin]['uis']['perf_label'].setText(
                    text)

            elif this_plugin == 'sysmon':
                hit = self.performances[this_plugin]['infos']['last'][
                    'hit_number']
                miss = self.performances[this_plugin]['infos']['last'][
                    'miss_number']
                rate = self.performances[this_plugin]['infos']['last'][
                    'hit_number'] / (
                        self.performances[this_plugin]['infos']['last']
                        ['hit_number'] + self.performances[this_plugin]
                        ['infos']['last']['miss_number']) if (
                            self.performances[this_plugin]['infos']['last']
                            ['hit_number'] + self.performances[this_plugin]
                            ['infos']['last']['miss_number']) != 0 else 1

                rate = round(rate * 100, 1)

                text = _(
                    "On average, you corrected %s out of %s of failures (%s%%)"
                ) % (hit, hit + miss, rate)
                self.performances[this_plugin]['uis'][
                    'perf_label'].setWordWrap(1)
                self.performances[this_plugin]['uis']['perf_label'].setText(
                    text)

            elif this_plugin == 'track':
                time_in_rate = float(
                    self.performances[this_plugin]['infos']['total']
                    ['time_in_ms']) / (
                        self.performances[this_plugin]['infos']['total']
                        ['time_in_ms'] + self.performances[this_plugin]
                        ['infos']['total']['time_out_ms']) if (
                            self.performances[this_plugin]['infos']['total']
                            ['time_in_ms'] + self.performances[this_plugin]
                            ['infos']['total']['time_out_ms']) != 0 else 1
                perc = round(time_in_rate * 100, 1)

                text = _("On average, you spent %s%% of time inside the target"
                         ) % perc

                self.performances[this_plugin]['uis'][
                    'perf_label'].setWordWrap(1)
                self.performances[this_plugin]['uis']['perf_label'].setText(
                    text)

        # Pause all, hide all the running task, but not their ui_label
        self.parent().onPause(hide_ui=False)
        for this_plugin in self.performances:
            self.performances[this_plugin]['uis']['perf_label'].show()
        self.show()

        self.feedback_timer.start(self.parameters['feedbackduration'] * 1000)
Exemplo n.º 25
0
    def getSchedule(self):
        """Read self.parent().scenariocontents. Schedules show manual mode phases"""

        schedules = dict(track=[], communications=[])

        for this_task in schedules.keys():
            this_dict = {
                key: value
                for key, value in self.parent().scenariocontents.items()
                if this_task in value
            }

            if any([['start'] in value[this_task]
                    for key, value in this_dict.items()]):
                starttime = [
                    key for key, value in this_dict.items()
                    if ['start'] in value[this_task]
                ][0]
                this_start = [
                    key for key, value in this_dict.items()
                    if ['start'] in value[this_task]
                ][0]
                try:
                    endtime = [
                        key for key, value in this_dict.items()
                        if 'stop' in value[this_task][0]
                    ][0]
                except:
                    self.parent().showCriticalMessage(
                        _("Can't compute schedule. No 'stop' signal found in scenario for the %s task"
                          ) % (this_task))

                # Browse scenario content in sorted order
                # While automaticsolver is OFF : manual/assisted mode is ON
                for this_time in sorted(this_dict):
                    if ['automaticsolver', 'True'
                        ] in this_dict[this_time][this_task] or [
                            'automaticsolver', 'False'
                        ] in this_dict[this_time][this_task]:
                        if ['automaticsolver',
                                'True'] in this_dict[this_time][this_task]:
                            this_end = this_time
                        elif ['automaticsolver',
                              'False'] in this_dict[this_time][this_task]:
                            this_start = this_time

                        if 'this_start' in locals() and 'this_end' in locals(
                        ) and this_start < this_end:
                            schedules[this_task].append([
                                self.dateStringToSecondInteger(this_start),
                                self.dateStringToSecondInteger(this_end)
                            ])
                if this_start < endtime and this_start != starttime:
                    schedules[this_task].append([
                        self.dateStringToSecondInteger(this_start),
                        self.dateStringToSecondInteger(endtime)
                    ])

                if len(schedules[this_task]) == 0:
                    schedules[this_task].append([
                        self.dateStringToSecondInteger(starttime),
                        self.dateStringToSecondInteger(endtime)
                    ])
        return schedules['track'], schedules['communications']
Exemplo n.º 26
0
    def LoadScales(self, scalefile):
        # Create dictionary to store scales information
        self.scales = {}

        # Load scales from file
        if not scalefile:
            self.parent().showCriticalMessage("No file to load!")
            return

        filename = os.path.join(self.parent().scales_directory, scalefile)

        if not os.path.exists(filename):
            self.parent().showCriticalMessage(
                _("Unable to find the scale file: '%s'") % filename)
            return

        self.scalesfile = open(filename, 'r')

        scale_number = -1
        for this_line in self.scalesfile:
            match = re.match(self.regex_scale_pattern, this_line)
            if match:
                scale_number += 1
                linecontent = this_line.split(';')
                self.scales[scale_number] = {}
                self.scales[scale_number]['label'] = linecontent[0]
                self.scales[scale_number]['title'] = linecontent[1]
                self.scales[scale_number]['minimumLabel'] = linecontent[
                    2].split('/')[0]
                self.scales[scale_number]['maximumLabel'] = linecontent[
                    2].split('/')[1]
                self.scales[scale_number]['minimumValue'] = int(
                    linecontent[3].split('/')[0])
                self.scales[scale_number]['maximumValue'] = int(
                    linecontent[3].split('/')[1])
                self.scales[scale_number]['defaultValue'] = int(
                    linecontent[3].split('/')[2].replace('\n', ''))

                if not self.scales[scale_number]['minimumValue'] < self.scales[
                        scale_number]['defaultValue'] < self.scales[
                            scale_number]['maximumValue']:
                    self.parent().showCriticalMessage(
                        _("Error in scales. Default value must be comprised between minimum and maximum. See in file: "
                          ) + self.parameters['filename'])

        if len(self.scales) == 0:
            self.parent().showCriticalMessage(
                _("Error in scales. No correctly formatted line found in the following file:"
                  ) + self.parameters['filename'])

        self.scalesfile.close()

        scale_width = self.screen_width / 3
        scale_height = (self.screen_height - (len(self.scales) *
                                              (50 + 30 + 40))) / 2
        scale_height = min(40, scale_height)  # Minimal height is 40
        current_y = 0

        self.layout = QtWidgets.QVBoxLayout(self)
        for scale_number in self.scales.keys():
            self.scales[scale_number]['uis'] = dict()
            unicode_string = self.scales[scale_number]['title']
            self.scales[scale_number]['uis'][
                'questionLabel'] = QtWidgets.QLabel(unicode_string)
            self.scales[scale_number]['uis']['questionLabel'].setFont(
                self.mainFont)
            self.scales[scale_number]['uis']['questionLabel'].setWordWrap(True)
            self.scales[scale_number]['uis']['questionLabel'].setAlignment(
                QtCore.Qt.AlignCenter)

            unicode_string = self.scales[scale_number]['minimumLabel']
            self.scales[scale_number]['uis'][
                'minimumLabel'] = QtWidgets.QLabel(unicode_string)
            self.scales[scale_number]['uis']['minimumLabel'].setAlignment(
                QtCore.Qt.AlignRight)
            self.scales[scale_number]['uis']['minimumLabel'].setFont(
                self.scaleFont)

            self.scales[scale_number]['uis']['slider'] = QtWidgets.QSlider(
                QtCore.Qt.Horizontal)
            self.scales[scale_number]['uis']['slider'].setMinimum(
                self.scales[scale_number]['minimumValue'])
            self.scales[scale_number]['uis']['slider'].setMaximum(
                self.scales[scale_number]['maximumValue'])
            self.scales[scale_number]['uis']['slider'].setTickInterval(1)
            self.scales[scale_number]['uis']['slider'].setTickPosition(
                QtWidgets.QSlider.TicksBothSides)
            self.scales[scale_number]['uis']['slider'].setValue(
                self.scales[scale_number]['defaultValue'])
            self.scales[scale_number]['uis']['slider'].setSingleStep(1)
            self.scales[scale_number]['uis']['slider'].setMaximumWidth(
                0.5 * self.screen_width)

            unicode_string = self.scales[scale_number]['maximumLabel']
            self.scales[scale_number]['uis'][
                'maximumLabel'] = QtWidgets.QLabel(unicode_string)
            self.scales[scale_number]['uis']['maximumLabel'].setAlignment(
                QtCore.Qt.AlignLeft)
            self.scales[scale_number]['uis']['maximumLabel'].setFont(
                self.scaleFont)

            hbox = QtWidgets.QHBoxLayout()
            hbox.addWidget(self.scales[scale_number]['uis']['questionLabel'])
            self.layout.addLayout(hbox)
            hbox = QtWidgets.QHBoxLayout()
            for this_element in ['minimumLabel', 'slider', 'maximumLabel']:
                vbox = QtWidgets.QVBoxLayout()
                vbox.addWidget(self.scales[scale_number]['uis'][this_element])
                vbox.setAlignment(QtCore.Qt.AlignVCenter)
                vbox.setContentsMargins(10, 0, 10, 0)
                hbox.addLayout(vbox)
            self.layout.addLayout(hbox)
            self.layout.addStretch(1)

        self.questionnairebtn = QtWidgets.QPushButton(_('Validate'))
        self.questionnairebtn.setMaximumWidth(0.25 * self.screen_width)
        self.questionnairebtn.clicked.connect(self.onClick)

        hbox = QtWidgets.QHBoxLayout()
        hbox.addWidget(self.questionnairebtn)
        self.layout.addLayout(hbox)
Exemplo n.º 27
0
    def onUpdate(self):

        if self.parameters['displayautomationstate']:
            self.refreshModeLabel()
        else:
            self.modeLabel.hide()

        if self.parameters['resetperformance'] is not None:
            if self.parameters['resetperformance'] in ['last', 'global']:
                for i in self.performance[self.parameters['resetperformance']]:
                    self.performance[
                        self.parameters['resetperformance']][i] = 0
            elif self.parameters['resetperformance'] is not None:
                self.parent().showCriticalMessage(
                    _("%s : wrong argument in sysmon;resetperformance") %
                    self.parameters['resetperformance'])
            self.parameters['resetperformance'] = None

        # For each light button, refresh name
        for thisLight, lightValues in self.parameters['lights'].items():
            lightValues['ui'].light.setText(lightValues['name'])

        # For each scale gauge, refresh name
        for thisScale, scaleValues in self.parameters['scales'].items():
            scaleValues['ui'].label.setText(scaleValues['name'])

        # 1. Check failures only if no failure is already occuring
        # (currently prevents double-failure !)
        if len(self.currentFailure) == 0:
            for gauge_type in ['lights', 'scales']:
                for gauge, gaugeValue in self.parameters[gauge_type].items():

                    # If a failure is to be initiated
                    if (gauge_type == 'scales' and gaugeValue['failure']
                            in ['up', 'down']) or (gauge_type == 'lights'
                                                   and gaugeValue['failure']):

                        # Start it...
                        self.startFailure(gauge_type, gauge)
                        # ...and leave the loop
                        break

        # 2. Vary position of each scale, depending on its state (up, down, no)
        for thisScale, scaleValues in self.parameters['scales'].items():
            scaleValues['position'] = self.computeNextPosition(thisScale)

            # 3. Refresh visual display
            if 'ui' in scaleValues:
                scaleValues['ui'].style = self.parameters['scalestyle']
                scaleValues['ui'].position = scaleValues['position']

        for thisLight, lightValues in self.parameters['lights'].items():
            if 'ui' in lightValues:
                lightValues['ui'].refreshState(lightValues['on'])

        # 4. Check for arbitrary feedbacks
        for f, v in self.parameters['feedbacks'].items():
            if v['trigger'] != 0:
                ui_idx = str(v['trigger'])
                if any([
                        ui_idx == idx
                        for idx, val in self.parameters['scales'].items()
                ]):
                    trigger_ui = self.parameters['scales'][ui_idx]['ui']
                    self.trigger_feedback(trigger_ui, f)
                    v['trigger'] = None
Exemplo n.º 28
0
    def onUpdate(self):

        if self.parameters['displayautomationstate']:
            self.refreshModeLabel()
        
        if self.parameters['resetperformance'] is not None:
            if self.parameters['resetperformance'] in ['last', 'global']:
                for this_index in self.performance[self.parameters['resetperformance']]:
                    self.performance[self.parameters['resetperformance']][this_index] = 0
            else:
                self.parent().showCriticalMessage(_("%s : wrong argument in resman;resetperformance") % self.parameters['resetperformance'])
            self.parameters['resetperformance'] = None

        time_resolution = (self.parameters['taskupdatetime'] / 1000) / 60.

        # 0. Compute automatic actions if heuristicsolver activated, three heuristics
        # Browse only woorking pumps (state != -1)

        if self.parameters['heuristicsolver'] or self.parameters['assistedsolver']:
            for this_pump in [pump for pump in self.parameters['pump'].keys() if self.parameters['pump'][pump]['state'] != -1]:
                fromtank = self.parameters['pump'][this_pump]['ui'].fromTank_label
                totank = self.parameters['pump'][this_pump]['ui'].toTank_label


                # 0.1. Systematically activate pumps draining non-depletable tanks
                if not self.parameters['tank'][fromtank]['depletable'] and self.parameters['pump'][this_pump]['state'] == 0 :
                    self.parameters['pump'][this_pump]['state'] = 1


                # 0.2. Activate/deactivate pump whose target tank is too low/high
                # "Too" means level is out of a tolerance zone around the target level (2500 +/- 150)
                if self.parameters['tank'][totank]['target'] is not None:
                    if self.parameters['tank'][totank]['level'] <= self.parameters['tank'][totank]['target'] - 150:
                        self.parameters['pump'][this_pump]['state'] = 1
                    elif self.parameters['tank'][totank]['level'] >= self.parameters['tank'][totank]['target'] + 150:
                        self.parameters['pump'][this_pump]['state'] = 0


                # 0.3. Equilibrate between the two A/B tanks if sufficient level
                if self.parameters['tank'][fromtank]['target'] is not None and self.parameters['tank'][totank]['target'] is not None:
                    if self.parameters['tank'][fromtank]['level'] >= self.parameters['tank'][totank]['target'] >= self.parameters['tank'][totank]['level']:
                        self.parameters['pump'][this_pump]['state'] = 1
                    else:
                        self.parameters['pump'][this_pump]['state'] = 0


        # 1. Deplete tanks A and B
        for thisTank in ['a', 'b']:
            volume = int(self.parameters['tank'][
                         thisTank]['lossperminute'] * time_resolution)
            volume = min(volume, self.parameters['tank'][thisTank][
                         'level'])  # If level less than volume, deplete only available level
            self.parameters['tank'][thisTank]['level'] -= volume

        # 2. For each pump
        for pumpNumber in self.parameters['pump'].keys():

            # 2.a Transfer flow if pump is ON
            if self.parameters['pump'][pumpNumber]['state'] == 1:

                fromtank, totank = self.parameters['pump'][pumpNumber]['ui'].fromTank_label, self.parameters['pump'][pumpNumber]['ui'].toTank_label

                # Compute volume
                volume = int(self.parameters['pump'][
                             pumpNumber]['flow']) * time_resolution

                # Check if this volume is available
                volume = min(
                    volume, self.parameters['tank'][fromtank]['level'])

                # Drain it from tank (if its capacity is limited)...
                if self.parameters['tank'][fromtank]['depletable']:
                    self.parameters['tank'][fromtank]['level'] -= int(volume)

                # ...to tank (if it's not full)
                volume = min(volume, self.parameters['tank'][totank][
                             'max'] - self.parameters['tank'][totank]['level'])
                self.parameters['tank'][totank]['level'] += int(volume)

            # 2.b Modify flows according to pump states
            elif self.parameters['pump'][pumpNumber]['state'] != 1 or self.parameters['pump'][pumpNumber]['hide']:  # (OFF | FAIL => 0)
                if self.parameters['pump'][pumpNumber]['state'] == -1 and not self.parameters['pump'][pumpNumber]['failLogged']:
                    self.buildLog(["STATE", "PUMP" + pumpNumber, "FAIL"])
                    self.parameters['pump'][pumpNumber]['failLogged'] = True

                if self.parameters['pump'][pumpNumber]['state'] == 0 and self.parameters['pump'][pumpNumber]['failLogged']:
                    self.parameters['pump'][pumpNumber]['failLogged'] = False
                    self.buildLog(["STATE", "PUMP" + pumpNumber, "OFF"])

        # 3. For each tank
        for thisTank in self.parameters['tank'].keys():
            pumps_to_deactivate = []

            # If it is full, select incoming pumps for deactivation
            if self.parameters['tank'][thisTank]['level'] >= self.parameters['tank'][thisTank]['max']:
                pumps_to_deactivate = [self.parameters['pump'].keys()[i] for i in range(
                    0, len(self.parameters['pump'])) if self.parameters['pump'][self.parameters['pump'].keys()[i]]['ui'].toTank_label == thisTank]

            # Likewise, if it is empty, select outcome pumps for deactivation
            elif self.parameters['tank'][thisTank]['level'] <= 0:
                pumps_to_deactivate = [self.parameters['pump'].keys()[i] for i in range(
                    0, len(self.parameters['pump'])) if self.parameters['pump'][self.parameters['pump'].keys()[i]]['ui'].fromTank_label == thisTank]

            # Deactivate selected pumps if not on failure
            for thisPump in pumps_to_deactivate:
                if not self.parameters['pump'][thisPump]['state'] == -1:  # if not Fail
                    self.parameters['pump'][thisPump]['state'] = 0
                    self.buildLog(["STATE", "PUMP" + thisPump, "OFF"])

        # 4. Refresh visual information
        for thisPump in self.parameters['pump'].keys():
            self.parameters['pump'][thisPump]['ui'].changeState(self.parameters['pump'][thisPump]['state'], self.parameters['pump'][thisPump]['hide'])

        for thisTank in self.parameters['tank'].keys():
            self.parameters['tank'][thisTank]['ui'].refreshLevel(self.parameters['tank'][thisTank]['level'])

        # 5. Log tank level if a target is set           
        for thisTank in self.parameters['tank'].keys():
            if self.parameters['tank'][thisTank]['target'] is not None:
                self.buildLog(["STATE", "TANK" + thisTank.upper(), "LEVEL", str(self.parameters['tank'][thisTank]['level'])])
                
                for this_cat in self.performance:
                    local_dev = abs(self.parameters['tank'][thisTank]['level'] - self.parameters['tank'][thisTank]['target'])
                    if local_dev <= self.parameters['tolerancelevel']:
                        self.performance[this_cat][thisTank.lower()+'_in']+=1
                    else:
                        self.performance[this_cat][thisTank.lower()+'_out']+=1
        self.update()
Exemplo n.º 29
0
    def __init__(self, parent):
        super(Task, self).__init__(parent)

        # SYSMON PARAMETERS ###
        self.parameters = {
            'title': 'System monitoring',
            'taskplacement': 'topleft',
            'taskupdatetime': 200,
            'alerttimeout': 10000,
            'automaticsolver': False,
            'automaticsolverdelay': 1 * 1000,
            'displayautomationstate': False,
            'allowanykey': False,
            'scalesnumofboxes': 11,  # Must be odd (to admit a middle position)
            'safezonelength': 3,
            'scalestyle': 1,  # could be defined at the scale level
            'resetperformance': None,
            'feedbacks': {
                'positive': {
                    'active': True,
                    'color': '#ffff00',
                    'duration': 1.5 * 1000,
                    'trigger': 0
                },
                'negative': {
                    'active': True,
                    'color': '#ff0000',
                    'duration': 1.5 * 1000,
                    'trigger': 0
                }
            },
            'lights': {
                '1': {
                    'name': 'F5',
                    'failure': False,
                    'on': True,
                    'default': 'on',
                    'oncolor': "#009900",
                    'keys': [QtCore.Qt.Key_F5]
                },
                '2': {
                    'name': 'F6',
                    'failure': False,
                    'on': False,
                    'default': 'off',
                    'oncolor': "#FF0000",
                    'keys': [QtCore.Qt.Key_F6]
                }
            },
            'scales': {
                '1': {
                    'name': 'F1',
                    'failure': 'no',
                    'keys': [QtCore.Qt.Key_F1]
                },
                '2': {
                    'name': 'F2',
                    'failure': 'no',
                    'keys': [QtCore.Qt.Key_F2]
                },
                '3': {
                    'name': 'F3',
                    'failure': 'no',
                    'keys': [QtCore.Qt.Key_F3]
                },
                '4': {
                    'name': 'F4',
                    'failure': 'no',
                    'keys': [QtCore.Qt.Key_F4]
                }
            }
        }

        self.performance = {
            'total': {
                'hit_number': 0,
                'miss_number': 0,
                'fa_number': 0
            },
            'last': {
                'hit_number': 0,
                'miss_number': 0,
                'fa_number': 0
            }
        }

        # Potentially translate task title
        self.parameters['title'] = _(self.parameters['title'])

        # Set the initial position of the cursor (middle)
        for thisScale, scaleValue in self.parameters['scales'].items():
            scaleValue['position'] = self.parameters['scalesnumofboxes'] / 2

        # Define two failures zones (up, down)
        totalRange = tuple(range(self.parameters['scalesnumofboxes']))

        self.zones = dict()
        self.zones['no'] = [int(median(totalRange))]
        while len(self.zones['no']) < self.parameters['safezonelength']:
            self.zones['no'].insert(0, min(self.zones['no']) - 1)
            self.zones['no'].insert(len(self.zones['no']),
                                    max(self.zones['no']) + 1)

        self.zones['up'] = [r for r in totalRange if r < min(self.zones['no'])]
        self.zones['down'] = [
            r for r in totalRange if r > max(self.zones['no'])
        ]

        # Set a list of accepted keys depending on lights and scales parameters
        scales_keys = [
            v['keys'][0] for s, v in self.parameters['scales'].items()
        ]
        lights_keys = [
            v['keys'][0] for l, v in self.parameters['lights'].items()
        ]
        self.accepted_keys = scales_keys + lights_keys
Exemplo n.º 30
0
    def onStart(self):
        if not iViewXAPI:
            self.parent().showCriticalMessage(
                _("Unable to load the eyetracker library!"))
            return

        self.parent().onPause()

        try:
            self.adress_iviewx = socket.gethostbyname(self.parameters['smiip'])
            print(self.adress_iviewx)
        except (socket.error, EOFError):
            self.parent().showCriticalMessage(
                _("Unable to find the eyetracker computer in the network!"))
            self.parent().onResume()
            return

        try:
            adress_local = socket.gethostbyname(socket.gethostname())
        except (socket.error, EOFError):
            self.parent().showCriticalMessage(
                _("Unable to find the eyetracker computer in the network!"))
            self.parent().onResume()
            return

        res = 0
        i = 0
        while res != 1 and i < self.parameters['connectmaxtries']:
            # Just in case the previous one did not stop anything
            try:
                iViewXAPI.iV_Disconnect()
            except:
                pass

            res = iViewXAPI.iV_Connect(self.adress_iviewx,
                                       self.parameters['smisendport'],
                                       adress_local,
                                       self.parameters['smireceiveport'])
            i += 1

        if res != 1:
            self.parent().showCriticalMessage(
                _("Unable to connect to the eyetracker!"))
            self.parent().onResume()
            return

        res = iViewXAPI.iV_GetSystemInfo(byref(systemData))
        self.taskUpdateTime = float(1000 / systemData.samplerate)

        # Calibration
        calibrationData = CCalibration(5, 1, 0, 0, 1, 30, 230, 1, 10)
        res = iViewXAPI.iV_SetupCalibration(byref(calibrationData))

        # Calibration loop
        calibration_accepted = False
        deviation_threshold = 0.5  # Maximum deviation angle accepted for calibration

        while not calibration_accepted:

            res = iViewXAPI.iV_Calibrate()

            res = iViewXAPI.iV_Validate()

            accuracyData = CAccuracy(0, 0, 0, 0)
            res = iViewXAPI.iV_GetAccuracy(byref(accuracyData), 1)
            meanDeviation = (
                accuracyData.deviationXLeft + accuracyData.deviationXRight +
                accuracyData.deviationYLeft + accuracyData.deviationYRight) / 4

            if meanDeviation <= deviation_threshold:
                calibration_accepted = True
            print('Mean deviation -> ' + str(meanDeviation))

        tempDict = {
            'sampleRate (Hz)':
            str(systemData.samplerate),
            'iViewX_version':
            str(systemData.iV_MajorVersion) + "." +
            str(systemData.iV_MinorVersion) + "." +
            str(systemData.iV_Buildnumber),
            'API_version':
            str(systemData.API_MajorVersion) + "." +
            str(systemData.API_MinorVersion) + "." +
            str(systemData.API_Buildnumber),
            'deviationXLeft':
            str(accuracyData.deviationXLeft),
            'deviationXRight':
            str(accuracyData.deviationXRight),
            'deviationYLeft':
            str(accuracyData.deviationYLeft),
            'deviationYRight':
            str(accuracyData.deviationYRight),
            'header':
            '\t'.join(
                [thisInfo for thisInfo in self.parameters['getFromSample']])
        }

        SMILOG_FILE_PATH = self.parent().LOG_FILE_PATH[:-4] + '_ET.log'
        self.sampleLog = Logger.Logger(self.parent(), SMILOG_FILE_PATH,
                                       tempDict)

        iViewXAPI.iV_SetLogger(1, "iViewX_log.txt")

        res = iViewXAPI.iV_SaveCalibration("save_calibration")

        try:
            res = iViewXAPI.iV_StopRecording()
        except:
            pass

        res = iViewXAPI.iV_StartRecording()
        if res != 1:
            self.parent().showCriticalMessage(
                _("Unable to start recording the eyetracker!"))
            return

        self.parent().onResume()