Exemple #1
0
    def set_run(self, run):
        '''
        Sets the run variable directly.
        Usually called at start up, when reading
        the run value from the ESP.

        arguments:
        - run: the run value (0 or 1) to set
        '''
        if self._run == run:
            return

        self._run = run

        if run == self.DONOT_RUN:
            # TODO: this should be an alarm
            msg = MessageBox()
            msg.critical(
                'STOPPING VENTILATION',
                'The hardware has stopped the ventilation.',
                'The microcontroller has stopped the ventilation by sending run = '
                + str(run),
                'The microcontroller has stopped the ventilation by sending run = '
                + str(run), {msg.Ok: self.show_start_button})()

        else:
            self.show_stop_button()
    def _raise_comm_error(self, message):
        """
        Opens an error window with 'message'.
        """

        # TODO: find a good exit point
        msg = MessageBox()
        msg.critical('COMMUNICATION ERROR',
                     'Error communicating with the hardware', message,
                     '** COMMUNICATION ERROR **',
                     {msg.Ok: lambda: sys.exit(-1)})()
Exemple #3
0
def test_MessageBox_Critical(qtbot):
    msg = MessageBox()

    def foo():
        pass

    callbacks = {msg.Ok: foo}

    msg.critical("CHANGE OF MODE",
                 "The ventilator changed from PSV to PCV mode.",
                 "The microcontroller raised the backup flag.", "", callbacks,
                 True)

    assert msg is not None
Exemple #4
0
    def _on_click_snooze(self):
        '''
        The callback function called when the alarm
        snooze button is clicked.
        '''

        if self._mode not in [WARNING, ERROR]:
            raise Exception('mode must be alarm or warning.')

        # Reset the alarms/warnings in the ESP
        # If the ESP connection fails at this
        # time, raise an error box
        try:
            if self._mode == ERROR:
                self._esp32.snooze_hw_alarm(self._code)
                self._alarm_h.snooze_alarm(self._code)
            else:
                self._esp32.reset_warnings()
                self._alarm_h.snooze_warning(self._code)
        except Exception as error:
            msg = MessageBox()
            fn = msg.critical("Critical",
                              "Severe hardware communication error",
                              str(error), "Communication error", {
                                  msg.Retry: lambda: self.ok_worker(mode),
                                  msg.Abort: lambda: None
                              })
            fn()
Exemple #5
0
    def thread_complete(self):
        '''
        Called when a thread ends.
        '''

        if self._running:
            print(
                "\033[91mERROR: The I/O thread finished! Going to start a new one...\033[0m"
            )
            self._n_attempts += 1
            self._running = False

            if self._n_attempts > 10:
                self._n_attempts = 0
                msg = MessageBox()

                # TODO: find a good exit point
                callbacks = {
                    msg.Retry: self.start_io_thread,
                    msg.Abort: lambda: sys.exit(-1)
                }

                fn = msg.critical("COMMUNICATION ERROR",
                                  "CANNOT COMMUNICATE WITH THE HARDWARE",
                                  "Check cable connections then click retry.",
                                  "COMMUNICATION ERROR", callbacks)
                fn()

            time.sleep(0.05)
            self.start_io_thread()
Exemple #6
0
    def ok_worker(self, mode):
        '''
        The callback function called when the alarm 
        or warning pop up window is closed by clicking
        on the Ok button.

        arguments:
        - mode: what this is closing, an 'alarm' or a 'warning'
        '''

        if mode not in ['alarm', 'warning']:
            raise Exception('mode must be alarm or warning.')

        if mode == 'alarm':
            self._alarm_raised = False
        else:
            self._warning_raised = False

        # Reset the alarms/warnings in the ESP
        # If the ESP connection fails at this
        # time, raise an error box
        try:
            if mode == 'alarm':
                self._esp32.reset_alarms()
            else:
                self._esp32.reset_warnings()
        except Exception as error:
            msg = MessageBox()
            fn = msg.critical("Critical",
                              "Severe hardware communication error",
                              str(error), "Communication error", {
                                  msg.Retry: lambda: self.ok_worker(mode),
                                  msg.Abort: lambda: None
                              })
            fn()
Exemple #7
0
    def handle_alarms(self):
        '''
        The callback method which is called periodically
        to check if the ESP raised any alarm or warning.
        If an alarm or warning is raised, a pop up
        window appears, showing the list of alarms and
        warnings. If more alarms or warnings add up, the
        window is updated automatically showing the latest
        errors.
        '''

        # Retrieve alarms and warnings from the ESP
        try:
            esp32alarm = self._esp32.get_alarms()
            esp32warning = self._esp32.get_warnings()
        except Exception as error:
            esp32alarm = None
            esp32warning = None
            err_msg = "Severe hardware communication error. "
            err_msg += "Cannot retrieve alarm and warning statuses from hardware."
            msg = MessageBox()
            fn = msg.critical("Critical", err_msg, str(error),
                              "Communication error", {
                                  msg.Retry: lambda: None,
                                  msg.Abort: lambda: None
                              })
            fn()

        #
        # ALARMS
        #
        if esp32alarm:
            errors = esp32alarm.strerror_all()
            errors_full = esp32alarm.strerror_all(append_err_no=True)

            alarm_codes = esp32alarm.get_alarm_codes()

            for alarm_code, err_str in zip(alarm_codes, errors):
                if alarm_code not in self._err_buttons:
                    btn = AlarmButton(ERROR, alarm_code, err_str,
                                      self._alarmlabel, self._snooze_btn)
                    self._alarmstack.addWidget(btn)
                    self._err_buttons[alarm_code] = btn

        #
        # WARNINGS
        #
        if esp32warning:
            errors = esp32warning.strerror_all()
            errors_full = esp32warning.strerror_all(append_err_no=True)

            warning_codes = esp32warning.get_alarm_codes()

            for warning_code, err_str in zip(warning_codes, errors):
                if warning_code not in self._war_buttons:
                    btn = AlarmButton(WARNING, warning_code, err_str,
                                      self._alarmlabel, self._snooze_btn)
                    self._alarmstack.addWidget(btn)
                    self._war_buttons[warning_code] = btn
    def set_run(self, run):
        '''
        Sets the run variable directly.
        Usually called at start up, when reading
        the run value from the ESP.
        '''
        if self.run == run:
            return

        if self.run == self.DO_RUN:
            msg = MessageBox()
            msg.critical('STOPPING VENTILATION',
                         'The hardware has stopped the ventilation.',
                         'The microcontroller has stopped the ventilation by sending run = '+str(run),
                         'The microcontroller has stopped the ventilation by sending run = '+str(run),
                         {msg.Ok: self._stop_abruptly})()

        else:
            self.toggle_start_stop()
Exemple #9
0
 def send_signal(self, mode, pause):
     '''
     Sends signal the appropriate signal the ESP
     to pause inpiration or expiration.
     '''
     try:
         if not self._data_h.set_data(mode, int(pause)):
             raise Exception('Call to set_data failed.')
     except Exception as error:
         msg = MessageBox()
         fn = msg.critical("Critical",
                           "Severe hardware communication error",
                           str(error), "Communication error",
                           {msg.Ok: lambda: self.stop_timer()})
         fn()
    def open_comm_error(self, error):
        '''
        Opens a message window if there is a communication error.
        '''
        msg = MessageBox()

        # TODO: find a good exit point
        callbacks = {
            msg.Retry: self._restart_timer,
            msg.Abort: lambda: sys.exit(-1)
        }

        fn = msg.critical(
            "COMMUNICATION ERROR", "CANNOT COMMUNICATE WITH THE HARDWARE",
            "Check cable connections then click retry.\n" + error,
            "COMMUNICATION ERROR", callbacks)
        fn()
Exemple #11
0
def start_gui():
    """
    Launch the MVM GUI
    """
    base_dir = os.path.dirname(__file__)
    settings_file = os.path.join(base_dir, 'default_settings.yaml')

    with open(settings_file) as mvm_settings:
        config = yaml.load(mvm_settings, Loader=yaml.FullLoader)
    print('Config:', yaml.dump(config), sep='\n')

    app = QtWidgets.QApplication(sys.argv)

    esp32 = None
    if 'fakeESP32' in sys.argv:
        print('******* Simulating communication with ESP32')
        esp32 = FakeESP32Serial(config)
    else:
        while True:
            try:
                err_msg = "Cannot communicate with port %s" % config['port']
                esp32 = ESP32Serial(config)
                break
            except SerialException as error:
                msg = MessageBox()
                retry = msg.critical("Do you want to retry?",
                                     "Severe hardware communication error",
                                     str(error) + err_msg, "Communication error",
                                     {msg.Retry: lambda: True,
                                      msg.Abort: lambda: sys.exit(-1)})
                if not retry():
                    break

    if esp32 is None:
        exit(-1)

    esp32.set("wdenable", 1)

    watchdog = QtCore.QTimer()
    watchdog.timeout.connect(esp32.set_watchdog)
    watchdog.start(config["wdinterval"] * 1000)

    window = MainWindow(config, esp32)
    window.show()
    app.exec_()
    esp32.set("wdenable", 0)
    def send_signal(self, mode, pause):
        """
        Sends signal the appropriate signal the ESP
        to pause inpiration or expiration.

        arguments:
        - mode: The pause mode (either 'pause_exhale' or 'pause_inhale')
        - pause: Boolean for paused or not paused
        """
        try:
            if not self._data_h.set_data(mode, int(pause)):
                raise Exception('Call to set_data failed.')
        except Exception as error:
            msg = MessageBox()
            confirm_func = msg.critical(
                "Critical", "Severe hardware communication error", str(error),
                "Communication error", {msg.Ok: lambda: self.stop_timer(mode)})
            confirm_func()
def connect_esp32(config):
    try:
        if 'fakeESP32' in sys.argv:
            print('******* Simulating communication with ESP32')
            err_msg = "Cannot setup FakeESP32Serial"
            esp32 = FakeESP32Serial(config)
            esp32.set("wdenable", 1)
        else:
            err_msg = "Cannot communicate with port %s" % config['port']
            esp32 = ESP32Serial(config)
            esp32.set("wdenable", 1)
    except Exception as error:
        msg = MessageBox()
        fn = msg.critical("Do you want to retry?",
                          "Severe hardware communication error",
                          str(error) + err_msg, "Communication error",
                          { msg.Retry: lambda: connect_esp32(config),
                            msg.Abort: lambda: None})
        return fn()

    return esp32
class AlarmHandler:
    '''
    This class starts a QTimer dedicated
    to checking is there are any errors
    or warnings coming from ESP32
    '''

    def __init__(self, config, esp32):
        '''
        Constructor

        arguments:
        - config: the dictionary storing the configuration
        - esp32: the esp32serial object
        '''

        self._config = config
        self._esp32 = esp32

        self._alarm_raised = False
        self._warning_raised = False

        self._msg_err = MessageBox()
        self._msg_war = MessageBox()

        self._alarm_timer = QtCore.QTimer()
        self._alarm_timer.timeout.connect(self.handle_alarms)
        self._alarm_timer.start(config["alarminterval"] * 1000)



    def handle_alarms(self):
        '''
        The callback method which is called periodically
        to check if the ESP raised any alarm or warning.
        If an alarm or warning is raised, a pop up
        window appears, showing the list of alarms and
        warnings. If more alarms or warnings add up, the
        window is updated automatically showing the latest
        errors.
        '''

        # Retrieve alarms and warnings from the ESP
        try:
            esp32alarm = self._esp32.get_alarms()
            esp32warning = self._esp32.get_warnings()
        except Exception as error:
            esp32alarm = None
            esp32warning = None
            err_msg = "Severe hardware communication error. "
            err_msg += "Cannot retrieve alarm and warning statuses from hardware."
            msg = MessageBox()
            fn = msg.critical("Critical",
                              err_msg,
                              str(error),
                              "Communication error",
                              { msg.Retry: lambda: None,
                                msg.Abort: lambda: None })
            fn()

        #
        # ALARMS
        #
        if esp32alarm:
            errors = esp32alarm.strerror_all()
            errors_full = esp32alarm.strerror_all(append_err_no=True)

            if not self._alarm_raised:
                self._alarm_raised = True
                self._msg_err.critical("ALARM",
                             " - ".join(errors),
                             "\n".join(errors_full),
                             "Alarm received.",
                             { self._msg_err.Ignore: lambda:
                                 self.ok_worker('alarm', esp32alarm) },
                             do_not_block=True)
                self._msg_err.move(0, 100)
                self._msg_err.open()
            else:
                # If the window is already opened, just change the text
                self._msg_err.setInformativeText(" - ".join(errors))
                self._msg_err.setDetailedText("\n".join(errors_full))
                self._msg_err.raise_()


        #
        # WARNINGS
        #
        if esp32warning:
            errors = esp32warning.strerror_all()
            errors_full = esp32warning.strerror_all(append_err_no=True)

            if not self._warning_raised:
                self._warning_raised = True
                self._msg_war.warning("WARNING",
                             " - ".join(errors),
                             "\n".join(errors_full),
                             "Warning received.",
                             { self._msg_war.Ok: lambda:
                                 self.ok_worker('warning', esp32warning) },
                             do_not_block=True)
                self._msg_war.move(0, 300)
                self._msg_war.open()
            else:
                # If the window is already opened, just change the text
                self._msg_war.setInformativeText(" - ".join(errors))
                self._msg_war.setDetailedText("\n".join(errors_full))
                self._msg_war.raise_()


    def ok_worker(self, mode, raised_ones):
        '''
        The callback function called when the alarm
        or warning pop up window is closed by clicking
        on the Ok button.

        arguments:
        - mode: what this is closing, an 'alarm' or a 'warning'
        '''

        if mode not in ['alarm', 'warning']:
            raise Exception('mode must be alarm or warning.')

        if mode == 'alarm':
            self._alarm_raised = False
        else:
            self._warning_raised = False

        # Reset the alarms/warnings in the ESP
        # If the ESP connection fails at this
        # time, raise an error box
        try:
            if mode == 'alarm':
                for alarm_code in raised_ones.unpack():
                    self._esp32.snooze_hw_alarm(alarm_code)
            else:
                self._esp32.reset_warnings()
        except Exception as error:
            msg = MessageBox()
            fn = msg.critical("Critical",
                              "Severe hardware communication error",
                              str(error),
                              "Communication error",
                              { msg.Retry: lambda: self.ok_worker(mode),
                                msg.Abort: lambda: None })
            fn()

    def raise_alarm(self):
        '''
        Raises an alarm in the ESP
        '''
        self._esp32.raise_gui_alarm()

    def stop_alarm(self, code):
        '''
        Stops an alarm in the ESP
        '''
        self._esp32.reset_alarms()
    def handle_alarms(self):
        '''
        The callback method which is called periodically
        to check if the ESP raised any alarm or warning.
        If an alarm or warning is raised, a pop up
        window appears, showing the list of alarms and
        warnings. If more alarms or warnings add up, the
        window is updated automatically showing the latest
        errors.
        '''

        # Retrieve alarms and warnings from the ESP
        try:
            esp32alarm = self._esp32.get_alarms()
            esp32warning = self._esp32.get_warnings()
        except Exception as error:
            esp32alarm = None
            esp32warning = None
            err_msg = "Severe hardware communication error. "
            err_msg += "Cannot retrieve alarm and warning statuses from hardware."
            msg = MessageBox()
            fn = msg.critical("Critical",
                              err_msg,
                              str(error),
                              "Communication error",
                              { msg.Retry: lambda: None,
                                msg.Abort: lambda: None })
            fn()

        #
        # ALARMS
        #
        if esp32alarm:
            errors = esp32alarm.strerror_all()
            errors_full = esp32alarm.strerror_all(append_err_no=True)

            if not self._alarm_raised:
                self._alarm_raised = True
                self._msg_err.critical("ALARM",
                             " - ".join(errors),
                             "\n".join(errors_full),
                             "Alarm received.",
                             { self._msg_err.Ignore: lambda:
                                 self.ok_worker('alarm', esp32alarm) },
                             do_not_block=True)
                self._msg_err.move(0, 100)
                self._msg_err.open()
            else:
                # If the window is already opened, just change the text
                self._msg_err.setInformativeText(" - ".join(errors))
                self._msg_err.setDetailedText("\n".join(errors_full))
                self._msg_err.raise_()


        #
        # WARNINGS
        #
        if esp32warning:
            errors = esp32warning.strerror_all()
            errors_full = esp32warning.strerror_all(append_err_no=True)

            if not self._warning_raised:
                self._warning_raised = True
                self._msg_war.warning("WARNING",
                             " - ".join(errors),
                             "\n".join(errors_full),
                             "Warning received.",
                             { self._msg_war.Ok: lambda:
                                 self.ok_worker('warning', esp32warning) },
                             do_not_block=True)
                self._msg_war.move(0, 300)
                self._msg_war.open()
            else:
                # If the window is already opened, just change the text
                self._msg_war.setInformativeText(" - ".join(errors))
                self._msg_war.setDetailedText("\n".join(errors_full))
                self._msg_war.raise_()
    def send_values_to_hardware(self):
        '''
        Sends the currently set values to the ESP
        '''

        settings_to_file = {}
        for param, btn in self._all_spinboxes.items():
            settings_to_file[param] = self._current_values[param]

            # value is the variable to be sent to the hardware,
            # so possibly converted from the settings
            if param in ['enable_backup', 'pcv_trigger_enable']:
                value = int(self._current_values[param])
            elif param == 'insp_expir_ratio':
                i_over_e = 1. / self._current_values[param]
                value = 1. / (i_over_e + 1)
            else:
                value = self._current_values[param]

            if 'conversion' in self._config[param]:
                value = value * self._config[param]['conversion']
                if self._debug:
                    print('Converting value for', param, 'from',
                          value / self._config[param].get('conversion', 1.),
                          'to', value)

            if self._debug: print('Setting value of', param, ':', value)

            # Update the value in the config file
            self._config[param]['current'] = self._current_values[param]

            # Set color to red until we know the value has been set.
            btn.setStyleSheet("color: red")

            esp_param_name = self._config['esp_settable_param'][param]

            # Finally, try to set the value to the ESP
            # Raise an error message if this fails.
            try:
                if self._data_h.set_data(esp_param_name, value):
                    # Now set the color to green, as we know it has been set
                    btn.setStyleSheet("color: green")
            except Exception as error:
                msg = MessageBox()
                msg.critical(
                    "Critical", "Severe Hardware Communication Error",
                    str(error), "Communication error", {
                        msg.Retry: lambda: self.send_values_to_hardware,
                        msg.Abort: lambda: sys.exit(-1)
                    })()

            if param == 'respiratory_rate':
                self.toolsettings_lookup["respiratory_rate"].update(value)
            elif param == 'insp_expir_ratio':
                self.toolsettings_lookup["insp_expir_ratio"].update(
                    self._current_values[param])
            elif param == 'insp_pressure':
                self.toolsettings_lookup["insp_pressure"].update(value)

        settings_file = SettingsFile(self._config["settings_file_path"])
        settings_file.store(settings_to_file)