Пример #1
0
    def __init__(self, config, esp32, *args, **kwargs):
        #pylint: disable=too-many-statements
        """
        Initializes the main window for the MVM GUI. See below for subfunction setup description.
        """

        super(MainWindow, self).__init__(*args, **kwargs)
        uifile = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                              "mainwindow.ui")

        uic.loadUi(uifile, self)

        self.config = config
        self.esp32 = esp32
        settings_file = SettingsFile(self.config["settings_file_path"])
        self.user_settings = settings_file.load()
        '''
        Start the alarm handler, which will check for ESP alarms
        '''
        # Instantiate the critical alarm handler meant for severe communications and hardware error
        self.critical_alarm_handler = CriticalAlarmHandler(self, esp32)
        self.alarm_h = AlarmHandler(
            self.config, self.esp32, self.alarmbar,
            self.critical_alarm_handler.call_system_failure)
        '''
        Get the toppane and child pages
        '''
        self.toppane = self.findChild(QtWidgets.QStackedWidget, "toppane")
        self.main = self.findChild(QtWidgets.QWidget, "main")
        self.initial = self.findChild(QtWidgets.QWidget, "initial")
        self.startup = self.findChild(QtWidgets.QWidget, "startup")
        self.criticalerrorpage = self.findChild(QtWidgets.QWidget,
                                                "criticalerrorpage")
        '''
        Get the center pane (plots) widgets
        '''
        self.centerpane = self.findChild(QtWidgets.QStackedWidget,
                                         "centerpane")
        self.plots_all = self.findChild(QtWidgets.QWidget, "plots_all")
        self.alarms_settings = self.findChild(QtWidgets.QWidget,
                                              "alarms_settings")
        '''
        Get the bottombar and child pages
        '''
        self.bottombar = self.findChild(QtWidgets.QStackedWidget, "bottombar")
        self.toolbar = self.findChild(QtWidgets.QWidget, "toolbar")
        self.menu = self.findChild(QtWidgets.QWidget, "menu")
        self.frozen_bot = self.findChild(QtWidgets.QWidget,
                                         "frozenplots_bottom")
        self.settingsbar = self.findChild(QtWidgets.QWidget, "settingsbar")
        self.specialbar = self.findChild(QtWidgets.QWidget, "specialbar")
        self.blank = self.findChild(QtWidgets.QWidget, "blank")
        self.settingsfork = self.findChild(QtWidgets.QWidget,
                                           "settingsforkbar")
        self.alarmsbar = self.findChild(QtWidgets.QWidget, "alarmsbar")
        self.numpadbar = self.findChild(QtWidgets.QWidget, "numpadbar")
        self.criticalerrorbar = self.findChild(QtWidgets.QWidget,
                                               "criticalerrorbar")
        '''
        Get the stackable bits on the right
        '''
        self.rightbar = self.main.findChild(QtWidgets.QStackedWidget,
                                            "rightbar")
        self.monitors_bar = self.main.findChild(QtWidgets.QWidget,
                                                "monitors_bar")
        self.frozen_right = self.main.findChild(QtWidgets.QWidget,
                                                "frozenplots_right")
        '''
        Get initial and startup buttons
        '''
        self.button_new_patient = self.initial.findChild(
            QtWidgets.QPushButton, "button_new_patient")
        self.button_resume_patient = self.initial.findChild(
            QtWidgets.QPushButton, "button_resume_patient")
        self.button_resume_patient.setEnabled(self.user_settings != {})

        self.button_start_settings = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_settings")
        self.button_start_vent = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_vent")
        self.button_start_test = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_test")
        '''
        Get toolbar widgets
        '''
        self.button_menu = self.toolbar.findChild(QtWidgets.QPushButton,
                                                  "button_menu")
        self.button_unlockscreen = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_unlockscreen")
        self.home_button = self.toolbar.findChild(QtWidgets.QWidget,
                                                  "home_button")
        self.goto_menu = self.toolbar.findChild(QtWidgets.QWidget, "goto_menu")
        self.goto_unlock = self.toolbar.findChild(QtWidgets.QWidget,
                                                  "goto_unlock")
        self.label_status = self.toolbar.findChild(QtWidgets.QLabel,
                                                   "label_status")

        # Get menu widgets and connect settings for the menu widget
        self.button_back = self.menu.findChild(QtWidgets.QPushButton,
                                               "button_back")
        self.button_settingsfork = self.menu.findChild(QtWidgets.QPushButton,
                                                       "button_settingsfork")
        self.button_startstop = self.menu.findChild(QtWidgets.QPushButton,
                                                    "button_startstop")
        self.button_autoassist = self.menu.findChild(QtWidgets.QPushButton,
                                                     "button_autoassist")
        self.button_specialops = self.menu.findChild(QtWidgets.QPushButton,
                                                     "button_specialops")

        self.button_alarms = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_alarms")
        self.button_settings = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_settings")
        self.button_lockscreen = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_lockscreen")
        self.button_backsettings = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_backsettings")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")

        self.button_freeze = self.specialbar.findChild(QtWidgets.QPushButton,
                                                       "button_freeze")
        self.button_backspecial = self.specialbar.findChild(
            QtWidgets.QPushButton, "button_backspecial")

        # Get frozen plots bottom bar widgets and connect
        self.button_unfreeze = self.frozen_bot.findChild(
            QtWidgets.QPushButton, "button_unfreeze")

        # Connect initial startup buttons
        self.button_resume_patient.pressed.connect(self.goto_resume_patient)
        self.button_new_patient.pressed.connect(self.goto_new_patient)
        self.button_start_vent.pressed.connect(self.goto_main)
        self.button_start_test.pressed.connect(self.goto_selftest)
        self.button_spiro_calib.pressed.connect(self.goto_spiro_calibration)
        self.button_start_settings.pressed.connect(self.goto_settings)

        # Connect back and menu buttons to toolbar and menu
        # This effectively defines navigation from the bottombar.

        # Toolbar
        self.button_menu.pressed.connect(self.show_menu)

        # Menu
        self.button_back.pressed.connect(self.show_toolbar)
        self.button_alarms.pressed.connect(self.goto_alarms)
        self.button_settingsfork.pressed.connect(self.show_settingsfork)
        self.button_specialops.pressed.connect(self.show_specialbar)

        # Settings
        self.button_settings.pressed.connect(self.goto_settings)
        self.button_lockscreen.pressed.connect(self.lock_screen)
        self.button_backsettings.pressed.connect(self.show_menu)

        # Special
        self.button_freeze.pressed.connect(self.freeze_plots)
        self.button_unfreeze.pressed.connect(self.unfreeze_plots)
        self.button_backspecial.pressed.connect(self.show_menu)

        # Confirmation bar
        self.messagebar = MessageBar(self)
        self.bottombar.insertWidget(self.bottombar.count(), self.messagebar)
        # Spirometer Calibration
        self.spiro_calib.connect_mainwindow_esp32(self, self.esp32)
        # Self Test
        self.self_test.connect_mainwindow_esp32_selftestbar(
            self, self.esp32, self.selftestbar)

        # Assign unlock screen button and setup state
        self.unlockscreen_interval = self.config['unlockscreen_interval']
        self.button_unlockscreen._state = 0
        self.button_unlockscreen.setAutoRepeat(True)
        self.button_unlockscreen.setAutoRepeatInterval(
            self.unlockscreen_interval)
        self.button_unlockscreen.clicked.connect(self.handle_unlock)

        self.numpad = NumPad(self)
        self.numpad.assign_code(self.config['unlockscreen_code'],
                                self.unlock_screen)

        self.numpad.button_back.pressed.connect(self.lock_screen)
        self.button_backalarms.pressed.connect(self.exit_alarms)

        #Instantiate the DataFiller, which takes
        #care of filling plots data
        self.data_filler = DataFiller(config)

        #Set up tool settings (bottom bar)

        #self.toolsettings[..] are the objects that hold min, max values for a given setting as
        #as the current value (displayed as a slider and as a number).
        toolsettings_names = {
            "toolsettings_1", "toolsettings_2", "toolsettings_3"
        }
        self.toolsettings = {}

        for name in toolsettings_names:
            toolsettings = self.toolbar.findChild(QtWidgets.QWidget, name)
            toolsettings.connect_config(config)
            self.toolsettings[name] = toolsettings

        # Set up data monitor/alarms (side bar) and plots

        #self.monitors[..] are the objects that hold monitor values and
        #thresholds for alarm min and max. The current value and
        #optional stats for the monitored value (mean, max) are set
        #here.
        # plot slot widget names
        self.plots = {}
        for name in config['plots']:
            plot = self.main.findChild(QtWidgets.QWidget, name)
            plot.setFixedHeight(130)
            self.data_filler.connect_plot(name, plot)
            self.plots[name] = plot

        # The monitored fields from the default_settings.yaml config file
        self.monitors = {}
        for name in config['monitors']:
            monitor = Monitor(name, config)
            self.monitors[name] = monitor
            self.data_filler.connect_monitor(monitor)

        # The alarms are from the default_settings.yaml config file
        # self.alarms = {}
        # for name in config['alarms']:
        #     alarm = GuiAlarm(name, config, self.monitors, self.alarm_h)
        #     self.alarms[name] = alarm
        self.gui_alarm = GuiAlarms(config, self.esp32, self.monitors)
        for monitor in self.monitors.values():
            monitor.connect_gui_alarm(self.gui_alarm)

        # Get displayed monitors
        self.monitors_slots = self.main.findChild(QtWidgets.QVBoxLayout,
                                                  "monitors_slots")
        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)

        # Connect the frozen plots
        # Requires building of an ordered array to associate the correct
        # controls with the plot.
        active_plots = []
        for slotname in self.plots:
            active_plots.append(self.plots[slotname])
        self.cursor = Cursor(active_plots)
        self.frozen_bot.connect_workers(self.data_filler, active_plots,
                                        self.cursor)
        self.frozen_right.connect_workers(active_plots, self.cursor)

        #Instantiate DataHandler, which will start a new
        #thread to read data from the ESP32. We also connect
        #the DataFiller to it, so the thread will pass the
        #data directly to the DataFiller, which will
        #then display them.
        self._data_h = DataHandler(config, self.esp32, self.data_filler,
                                   self.gui_alarm)

        self.specialbar.connect_datahandler_config_esp32(
            self._data_h, self.config, self.esp32, self.messagebar)

        #Connect settings button to Settings overlay.
        self.settings = Settings(self)
        self.toppane.insertWidget(self.toppane.count(), self.settings)

        #Set up start/stop auto/min mode buttons.

        #Connect each to their respective mode toggle functions.
        #The StartStopWorker class takes care of starting and stopping a run

        self._start_stop_worker = StartStopWorker(self, self.config,
                                                  self.esp32,
                                                  self.button_startstop,
                                                  self.button_autoassist,
                                                  self.toolbar, self.settings)

        if self._start_stop_worker.is_running():
            self.goto_main()

        self.button_startstop.released.connect(
            self._start_stop_worker.toggle_start_stop)
        self.button_autoassist.released.connect(
            self._start_stop_worker.toggle_mode)
        self.gui_alarm.connect_workers(self._start_stop_worker)
    def __init__(self,
                 config,
                 main_path,
                 mode='normal',
                 diagnostic=False,
                 verbose=False,
                 simulation=False,
                 logdata=False,
                 *args,
                 **kwargs):
        """
        Initializes the main window
        """

        super(MainWindow, self).__init__(*args, **kwargs)
        uic.loadUi('mainwindow.ui', self)  # Load the .ui file

        # set mode
        if mode.lower() == 'debug':
            self.fast_update_time = 100
            self.fslow_update_time = 1000
            self.mode_verbose = True

        else:
            self.fast_update_time = 10
            self.slow_update_time = 1000
            self.mode_verbose = False

        # show full screen if running on a raspberry pi
        if 'raspberrypi' in os.uname():
            self.showFullScreen()

        # configuration
        self.config = config

        # data filler
        self.data_filler = data_filler.DataFiller(config=self.config)

        # run in verbose mode? do this if requested specifically or if running in debug mode
        self.verbose = (verbose) or (self.mode_verbose)

        # define the top level main path
        self.main_path = main_path
        if self.verbose:
            print(f"main: main path = {self.main_path}")

        # define the slow and fast data classes that hold the data generated by the loops
        self.time_to_display = 10  #seconds
        self.num_samples = int(self.time_to_display * 1000 /
                               self.fast_update_time)

        #hold an index about where in the plot (ie an index within num_samples) to put the next data
        self.index = 0

        self.fastdata = data_handler.fast_data()
        self.slowdata = data_handler.slow_data()
        self.breathdata = data_handler.breath_data()
        self.breathpar = data_handler.breath_par()

        # Start up the fast loop (data acquisition)
        self.fast_loop = data_handler.fast_loop(main_path=self.main_path,
                                                config=self.config,
                                                simulation=simulation,
                                                logdata=logdata,
                                                verbose=self.verbose)

        # once the sensor is initialized, start the fastloop
        self.sensor_initialized.connect(self.start_fastloop)
        while True:
            if self.fast_loop.sensor.initialized:
                self.sensor_initialized.emit()
                print(
                    'fastloop: sensor initialized. safe to start data acquisition: '
                )

                break

        # if the fastloop signals it has new data, grab it
        self.fast_loop.newdata.connect(self.update_fast_data)

        # start up the slow loop (calculations)
        self.slow_loop = data_handler.slow_loop(main_path=self.main_path,
                                                config=self.config,
                                                verbose=self.verbose)
        self.slow_loop.start()
        self.slow_loop.new_slowdata.connect(self.update_slow_data)
        #self.restart_looping_plot.connect(self.fast_loop.sensor.update_ambient_pressure)
        self.slow_loop.new_breathpar.connect(self.update_breath_params)
        # if the slowloop requests new data, send it the current fastdata
        self.slow_loop.request_fastdata.connect(self.slowloop_request)
        self.request_from_slowloop.connect(self.slow_loop.update_fast_data)

        # rezero the volume offset
        #self.update_vol_offset.connect(self.fast_loop.update_vol_offset)
        #self.update_vol_offset.connect(self.fast_loop.update_flow_trend)
        #self.update_vol_offset.connect(self.fast_loop.update_vol_trend)
        #self.update_vol_offset.connect(self.fast_loop.restart_integral)

        # if new breath detected tell fastloop to reset the integral
        #self.restart_looping_plot.connect(self.fast_loop.update_vol_trend)

        #if new breath data is received from fastloop, pass it to slowloop and ask for the breath params to be calculated
        self.new_breath_data.connect(self.slow_loop.calculate_breath_params)

        # if a new sensor calibration is selected, pass the new selection to fastdata.sensor
        self.new_sensor_cal.connect(self.fast_loop.sensor.set_mouthpiece)

        # if the fastloop sends new breath data, populate the mainloop breathdata
        self.fast_loop.new_breath.connect(self.update_breath_data)
        self.fast_loop.new_breath.connect(self.slow_loop.update_breath_data)

        # want to just show the plots to dewbug the calculations?
        self.diagnostic = diagnostic
        ### GUI stuff ###
        self.setWindowTitle("Open Respiratory Monitor")
        '''
        Get the toppane and child pages
        '''
        #self.toppane = self.findChild(QtWidgets.QStackedWidget, "toppane")
        self.main = self.findChild(QtWidgets.QWidget, "main")
        #self.initial = self.findChild(QtWidgets.QWidget, "initial")
        #self.startup = self.findChild(QtWidgets.QWidget, "startup")
        self.alarmbar = self.findChild(QtWidgets.QWidget, "alarmbar")
        self.toolbar = self.findChild(QtWidgets.QWidget, "toolbar")
        self.calpage = self.findChild(QtWidgets.QWidget, "calibration")
        self.statspage = self.findChild(QtWidgets.QWidget, "statspage")
        self.rezero_page = self.findChild(QtWidgets.QWidget, "rezero_page")
        '''
        Get the center pane (plots) widgets
        '''
        self.centerpane = self.findChild(QtWidgets.QStackedWidget,
                                         "centerpane")
        self.plots_all = self.findChild(QtWidgets.QWidget, "plots_all")
        self.plots_loops = self.centerpane.findChild(QtWidgets.QWidget,
                                                     "plots_loops")

        self.plots = {}
        for name in self.config['plots']:
            plot = self.main.findChild(QtWidgets.QWidget, name)
            self.data_filler.connect_plot(name, plot)
            self.plots[name] = plot

        # set up the loop plots
        self.plot_left = self.plots_loops.findChild(QtWidgets.QWidget,
                                                    "plot_left")
        self.plot_right = self.plots_loops.findChild(QtWidgets.QWidget,
                                                     "plot_right")

        labelStyle = {
            'color': self.config['axis_line_color'],
            'font-size': '18pt'
        }
        self.plot_left.setLabel(
            'left', self.config['monitors']['tidal_volume']['name'] + '' +
            self.config['monitors']['tidal_volume']['units'], **labelStyle)
        self.plot_left.setLabel(
            'bottom',
            'Pressure' + '' + self.config['monitors']['peep']['units'],
            **labelStyle)
        self.plot_right.setLabel(
            'left', self.config['monitors']['flow']['name'] + '' +
            self.config['monitors']['tidal_volume']['units'], **labelStyle)
        self.plot_right.setLabel(
            'bottom',
            'Pressure' + '' + self.config['monitors']['peep']['units'],
            **labelStyle)

        # Remove mouse interaction with plots
        self.plot_left.setMouseEnabled(x=False, y=False)
        self.plot_left.setMenuEnabled(False)
        self.plot_right.setMouseEnabled(x=False, y=False)
        self.plot_right.setMenuEnabled(False)

        yellow = pg.mkPen(color='y', width=2)
        pink = pg.mkPen(color='m', width=2)
        blue = pg.mkPen(color='b', width=2)
        green = pg.mkPen(color='g', width=2)

        # define the curves to plot
        self.line_left = self.plot_left.plot([0], [0], pen=yellow)
        self.line_right = self.plot_right.plot([0], [0], pen=blue)
        '''
        Get the alarm-related stuff
        '''
        self.alarms_settings = self.findChild(QtWidgets.QWidget,
                                              "alarms_settings")
        self.alarmsbar = self.findChild(QtWidgets.QWidget, "alarmsbar")
        '''
        Get the stackable bits on the right
        '''
        self.rightbar = self.main.findChild(QtWidgets.QStackedWidget,
                                            "rightbar")
        self.monitors_bar = self.main.findChild(QtWidgets.QWidget,
                                                "monitors_bar")
        self.frozen_right = self.main.findChild(QtWidgets.QWidget,
                                                "frozenplots_right")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")
        '''
        Get the bar at the bottom
        '''

        self.frozen_bot = self.findChild(QtWidgets.QWidget,
                                         "frozenplots_bottom")
        # Get frozen plots bottom bar widgets and connect
        self.button_unfreeze = self.frozen_bot.findChild(
            QtWidgets.QPushButton, "button_unfreeze")

        self.settingsfork = self.findChild(QtWidgets.QWidget,
                                           "settingsforkbar")
        self.button_alarms = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_alarms")
        self.button_arm = self.settingsfork.findChild(QtWidgets.QPushButton,
                                                      "button_arm")

        self.button_silence = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_silence")

        self.button_freeze = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_freeze")

        self.button_tools = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_tools")
        self.button_viewwaves = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_viewwaves")
        self.button_viewloops = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_viewloops")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")
        '''
        # stats bar
        '''
        self.statsbar = self.findChild(QtWidgets.QWidget, "statsbar")
        self.button_backstats = self.statsbar.findChild(
            QtWidgets.QPushButton, "button_back")
        self.button_tidal = self.statsbar.findChild(QtWidgets.QPushButton,
                                                    "button_tidal")
        self.button_peak = self.statsbar.findChild(QtWidgets.QPushButton,
                                                   "button_peak")
        self.button_peep = self.statsbar.findChild(QtWidgets.QPushButton,
                                                   "button_peep")

        self.button_resetstats = self.statspage.findChild(
            QtWidgets.QPushButton, "button_resetstats")
        '''
        stats page
        '''
        self.stats_name = self.statspage.findChild(QtWidgets.QLabel,
                                                   "name_parameter")
        self.stats_mean = self.statspage.findChild(QtWidgets.QLabel,
                                                   "num_mean")
        self.stats_min = self.statspage.findChild(QtWidgets.QLabel, "num_min")
        self.stats_max = self.statspage.findChild(QtWidgets.QLabel, "num_max")
        self.stats_pcterr = self.statspage.findChild(QtWidgets.QLabel,
                                                     "num_pcterror")
        self.stats_stderr = self.statspage.findChild(QtWidgets.QLabel,
                                                     "num_stderror")
        self.stats_units = self.statspage.findChild(QtWidgets.QLabel,
                                                    "num_units")
        self.statplot = self.statspage.findChild(QtWidgets.QWidget,
                                                 "plot_stats")
        self.button_resetstats = self.statspage.findChild(
            QtWidgets.QPushButton, "button_resetstats")

        # make the plot
        pen = pg.mkPen(color='y', width=2)
        pen = pg.mkPen(None)
        self.statline = self.statplot.plot([0], [0],
                                           pen=pen,
                                           symbol='o',
                                           symbolSize=20,
                                           symbolBrush=('y'))

        # set up the statistics set which will hold useful statistics about the breaths
        self.statset = Statset()
        for name in self.config['statistics']:
            self.statset.add_stat(name)
            #print("found statistic: ",name)
        # set the current stat that will be shown (by default its the first one in the config)
        self.current_stat = self.config['statistics'][0]
        print('mainloop: current stat = ', self.current_stat)
        self.set_displayed_stat(self.current_stat)
        '''
        # toolbar buttons
        '''

        self.button_backsettings = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_back")

        self.button_calsettings = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_calsettings")

        self.button_hamilton = self.calpage.findChild(QtWidgets.QPushButton,
                                                      "button_hamilton")
        self.button_iqspiro = self.calpage.findChild(QtWidgets.QPushButton,
                                                     "button_iqspiro")

        self.button_stats = self.toolbar.findChild(QtWidgets.QPushButton,
                                                   "button_stats")

        self.button_rezero = self.calpage.findChild(QtWidgets.QPushButton,
                                                    "button_rezero")
        self.button_rezero_yes = self.rezero_page.findChild(
            QtWidgets.QPushButton, "button_rezero_yes")
        self.button_rezero_no = self.rezero_page.findChild(
            QtWidgets.QPushButton, "button_rezero_no")
        self.num_p1 = self.rezero_page.findChild(QtWidgets.QLabel, "num_p1")
        self.num_p2 = self.rezero_page.findChild(QtWidgets.QLabel, "num_p2")
        '''
        Frozen Plot menu
        '''

        # Connect the frozen plots
        # Requires building of an ordered array to associate the correct
        # controls with the plot.
        active_plots = []
        for slotname in self.plots:
            active_plots.append(self.plots[slotname])
        self.cursor = Cursor(active_plots)
        self.frozen_bot.connect_workers(self.data_filler, active_plots,
                                        self.cursor)
        self.frozen_right.connect_workers(active_plots, self.cursor)

        # Frozen Plots
        self.button_freeze.pressed.connect(self.freeze_plots)
        self.button_unfreeze.pressed.connect(self.unfreeze_plots)
        '''
        Define the monitors
        '''

        # The monitored fields from the default_settings.yaml config file
        self.monitors = {}
        for name in config['monitors']:
            monitor = Monitor(name, config)
            self.monitors[name] = monitor
            self.data_filler.connect_monitor(monitor)
        # Get displayed monitors
        self.monitors_slots = self.main.findChild(QtWidgets.QVBoxLayout,
                                                  "monitors_slots")
        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)
        '''
        Start the alarm handler, which will check for ESP alarms
        '''
        self.alarm_h = AlarmHandler(self.config, self.alarmbar)

        # The alarms are from the default_settings.yaml config file
        # self.alarms = {}
        # for name in config['alarms']:
        #     alarm = GuiAlarm(name, config, self.monitors, self.alarm_h)
        #     self.alarms[name] = alarm
        self.gui_alarm = GuiAlarms(config, self.monitors)

        print('trying to connect alarms')
        for monitor in self.monitors.values():
            monitor.connect_gui_alarm(self.gui_alarm)
        '''
        Connect the menu buttons to actions
        '''
        self.button_alarms.pressed.connect(self.goto_alarms)

        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)
        self.button_backalarms.pressed.connect(self.exit_alarms)

        self.button_viewloops.pressed.connect(self.show_loops)
        self.button_viewwaves.pressed.connect(self.show_waveforms)

        #self.button_zero_flow.pressed.connect(self.zero_sensor_flow)

        # toolbar
        self.button_tools.pressed.connect(self.show_toolbar)
        self.button_backsettings.pressed.connect(self.exit_alarms)
        self.button_calsettings.pressed.connect(self.goto_calsettings)
        self.button_stats.pressed.connect(self.goto_stats)
        self.button_backstats.pressed.connect(self.show_toolbar)

        # calibration selection
        self.button_hamilton.toggled.connect(self.togglecal_hamilton)
        self.button_iqspiro.toggled.connect(self.togglecal_iqspiro)
        self.button_rezero.pressed.connect(self.goto_rezero_page)
        self.button_rezero_yes.pressed.connect(self.rezero_sensor)
        self.button_rezero_no.pressed.connect(self.goto_calsettings)
        self.button_rezero_no.pressed.connect(self.show_toolbar)

        # stats page
        self.button_tidal.pressed.connect(
            lambda: self.set_displayed_stat('tidal_volume'))
        self.button_peak.pressed.connect(
            lambda: self.set_displayed_stat('peak'))
        self.button_peep.pressed.connect(
            lambda: self.set_displayed_stat('peep'))
        self.button_resetstats.pressed.connect(self.reset_stats)
        ''' 
        arming the alarms
        '''
        self.button_arm.toggled.connect(self.arm_disarm_alarms)
        # set up the mute audio alarm buttion
        self.button_silence.pressed.connect(self.silence_alarms)

        # Show the Page
        self.goto_main()
        self.show_settingsfork()

        ### Stuff from the original just plots gui ###
        if self.diagnostic:
            self.graph0 = pg.PlotWidget()
            self.graph1 = pg.PlotWidget()
            self.graph2 = pg.PlotWidget()
            self.graph3 = pg.PlotWidget()

            layout = QtWidgets.QVBoxLayout()
            layout.addWidget(self.graph0)
            layout.addWidget(self.graph1)
            layout.addWidget(self.graph2)
            layout.addWidget(self.graph3)

            widget = QtWidgets.QWidget()
            widget.setLayout(layout)

            # make the window with a graph widget
            self.setCentralWidget(widget)

            # set the plot properties
            self.graph0.setBackground('k')
            self.graph0.showGrid(x=True, y=True)
            self.graph1.setBackground('k')
            self.graph1.showGrid(x=True, y=True)
            self.graph2.setBackground('k')
            self.graph2.showGrid(x=True, y=True)
            self.graph3.setBackground('k')
            self.graph3.showGrid(x=True, y=True)

            # Set the label properties with valid CSS commands -- https://groups.google.com/forum/#!topic/pyqtgraph/jS1Ju8R6PXk
            labelStyle = {'color': '#FFF', 'font-size': '12pt'}
            self.graph0.setLabel('left', 'Inspiring', 'cmH20', **labelStyle)
            self.graph1.setLabel('left', 'Flow ', 'L/m', **labelStyle)
            self.graph2.setLabel('left', 'Flow Slope', 'L/m/s', **labelStyle)
            self.graph3.setLabel('left', 'V', 'mL', **labelStyle)
            self.graph3.setLabel('bottom', 'Time', 's', **labelStyle)

            # change the plot range
            #self.graph1.setYRange(-10,40,padding = 0.1)
            #self.graph2.setYRange(-100,100,padding = 0.1)
            #self.graph3.setYRange(0,750,padding = 0.1)

            # make a QPen object to hold the marker properties
            yellow = pg.mkPen(color='y', width=2)
            pink = pg.mkPen(color='m', width=2)
            blue = pg.mkPen(color='b', width=2)
            green = pg.mkPen(color='g', width=2)

            # define the curves to plot
            self.data_line0 = self.graph0.plot(self.fastdata.dt,
                                               self.fastdata.p1,
                                               pen=yellow)
            self.data_line1 = self.graph1.plot(self.fastdata.dt,
                                               self.fastdata.flow,
                                               pen=blue)
            #self.data_line1b = self.graph1.plot(self.fastdata.dt,   self.fastdata.p2, pen = bluepen)
            self.data_line2 = self.graph2.plot(self.fastdata.dt,
                                               self.fastdata.dflow,
                                               pen=pink)
            self.data_line3 = self.graph3.plot(self.fastdata.dt,
                                               self.fastdata.vol * 1000,
                                               pen=green)

        # update the graphs at regular intervals (so it runs in a separate thread!!)
        # Stuff with the timer
        self.t_update = self.config[
            'plot_interval']  #self.fast_update_time*5 #update time of timer in ms
        self.timer = QtCore.QTimer()
        self.timer.setInterval(self.t_update)
        self.timer.timeout.connect(self.update_plots)
        self.timer.start()
Пример #3
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, config, esp32, *args, **kwargs):
        """
        Initializes the main window for the MVM GUI. See below for subfunction setup description.
        """

        super(MainWindow, self).__init__(*args, **kwargs)
        uic.loadUi('mainwindow.ui', self)  # Load the .ui file

        self.config = config
        self.esp32 = esp32
        settings_file = SettingsFile(self.config["settings_file_path"])
        self.user_settings = settings_file.load()
        '''
        Start the alarm handler, which will check for ESP alarms
        '''
        self.alarm_h = AlarmHandler(self.config, self.esp32)
        '''
        Get the toppane and child pages
        '''
        self.toppane = self.findChild(QtWidgets.QStackedWidget, "toppane")
        self.main = self.findChild(QtWidgets.QWidget, "main")
        self.initial = self.findChild(QtWidgets.QWidget, "initial")
        self.startup = self.findChild(QtWidgets.QWidget, "startup")
        '''
        Get the center pane (plots) widgets
        '''
        self.centerpane = self.findChild(QtWidgets.QStackedWidget,
                                         "centerpane")
        self.plots_all = self.findChild(QtWidgets.QWidget, "plots_all")
        self.alarms_settings = self.findChild(QtWidgets.QWidget,
                                              "alarms_settings")
        '''
        Get the bottombar and child pages
        '''
        self.bottombar = self.findChild(QtWidgets.QStackedWidget, "bottombar")
        self.toolbar = self.findChild(QtWidgets.QWidget, "toolbar")
        self.menu = self.findChild(QtWidgets.QWidget, "menu")
        self.frozen_bot = self.findChild(QtWidgets.QWidget,
                                         "frozenplots_bottom")
        self.settingsbar = self.findChild(QtWidgets.QWidget, "settingsbar")
        self.specialbar = self.findChild(QtWidgets.QWidget, "specialbar")
        self.blank = self.findChild(QtWidgets.QWidget, "blank")
        self.settingsfork = self.findChild(QtWidgets.QWidget,
                                           "settingsforkbar")
        self.alarmsbar = self.findChild(QtWidgets.QWidget, "alarmsbar")
        self.numpadbar = self.findChild(QtWidgets.QWidget, "numpadbar")
        '''
        Get the stackable bits on the right
        '''
        self.rightbar = self.main.findChild(QtWidgets.QStackedWidget,
                                            "rightbar")
        self.monitors_bar = self.main.findChild(QtWidgets.QWidget,
                                                "monitors_bar")
        self.frozen_right = self.main.findChild(QtWidgets.QWidget,
                                                "frozenplots_right")
        '''
        Get initial and startup buttons
        '''
        self.button_new_patient = self.initial.findChild(
            QtWidgets.QPushButton, "button_new_patient")
        self.button_resume_patient = self.initial.findChild(
            QtWidgets.QPushButton, "button_resume_patient")
        self.button_resume_patient.setEnabled(self.user_settings != {})

        self.button_start_settings = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_settings")
        self.button_start_vent = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_vent")
        self.button_start_test = self.startup.findChild(
            QtWidgets.QPushButton, "button_start_test")
        '''
        Get toolbar widgets
        '''
        self.button_menu = self.toolbar.findChild(QtWidgets.QPushButton,
                                                  "button_menu")
        self.button_unlockscreen = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_unlockscreen")
        self.home_button = self.toolbar.findChild(QtWidgets.QWidget,
                                                  "home_button")
        self.goto_menu = self.toolbar.findChild(QtWidgets.QWidget, "goto_menu")
        self.goto_unlock = self.toolbar.findChild(QtWidgets.QWidget,
                                                  "goto_unlock")
        self.label_status = self.toolbar.findChild(QtWidgets.QLabel,
                                                   "label_status")

        toolsettings_names = {
            "toolsettings_1", "toolsettings_2", "toolsettings_3"
        }
        self.toolsettings = {}

        for name in toolsettings_names:
            toolsettings = self.toolbar.findChild(QtWidgets.QWidget, name)
            toolsettings.connect_config(config)
            self.toolsettings[name] = toolsettings
        '''
        Get menu widgets and connect settings for the menu widget
        '''
        self.button_back = self.menu.findChild(QtWidgets.QPushButton,
                                               "button_back")
        self.button_settingsfork = self.menu.findChild(QtWidgets.QPushButton,
                                                       "button_settingsfork")
        self.button_startstop = self.menu.findChild(QtWidgets.QPushButton,
                                                    "button_startstop")
        self.button_autoassist = self.menu.findChild(QtWidgets.QPushButton,
                                                     "button_autoassist")
        self.button_specialops = self.menu.findChild(QtWidgets.QPushButton,
                                                     "button_specialops")

        self.button_alarms = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_alarms")
        self.button_settings = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_settings")
        self.button_lockscreen = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_lockscreen")
        self.button_backsettings = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_backsettings")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")

        self.button_freeze = self.specialbar.findChild(QtWidgets.QPushButton,
                                                       "button_freeze")
        self.button_backspecial = self.specialbar.findChild(
            QtWidgets.QPushButton, "button_backspecial")
        '''
        Get frozen plots bottom bar widgets and connect
        '''
        self.button_unfreeze = self.frozen_bot.findChild(
            QtWidgets.QPushButton, "button_unfreeze")
        '''
        Connect initial startup buttons
        '''
        self.button_resume_patient.pressed.connect(self.goto_resume_patient)
        self.button_new_patient.pressed.connect(self.goto_new_patient)
        self.button_start_vent.pressed.connect(self.goto_main)
        # TODO: connect to circuit test on ESP
        # self.button_start_test.pressed.connect()
        self.button_start_settings.pressed.connect(self.goto_settings)
        '''
        Connect back and menu buttons to toolbar and menu

        This effectively defines navigation from the bottombar.
        '''
        # Toolbar
        self.button_menu.pressed.connect(self.show_menu)

        # Menu
        self.button_back.pressed.connect(self.show_toolbar)
        self.button_alarms.pressed.connect(self.goto_alarms)
        self.button_settingsfork.pressed.connect(self.show_settingsfork)
        self.button_specialops.pressed.connect(self.show_specialbar)

        # Settings
        self.button_settings.pressed.connect(self.goto_settings)
        self.button_lockscreen.pressed.connect(self.lock_screen)
        self.button_backsettings.pressed.connect(self.show_menu)

        # Special
        self.button_freeze.pressed.connect(self.freeze_plots)
        self.button_unfreeze.pressed.connect(self.unfreeze_plots)
        self.button_backspecial.pressed.connect(self.show_menu)

        # Assign unlock screen button and setup state
        self.unlockscreen_interval = self.config['unlockscreen_interval']
        self.button_unlockscreen._state = 0
        self.button_unlockscreen.setAutoRepeat(True)
        self.button_unlockscreen.setAutoRepeatInterval(
            self.unlockscreen_interval)
        self.button_unlockscreen.clicked.connect(self.handle_unlock)

        self.numpad = NumPad(self)
        self.numpad.assign_code(self.config['unlockscreen_code'],
                                self.unlock_screen)

        self.numpad.button_back.pressed.connect(self.lock_screen)
        self.button_backalarms.pressed.connect(self.exit_alarms)
        '''
        Instantiate the DataFiller, which takes
        care of filling plots data
        '''
        self.data_filler = DataFiller(config)
        '''
        Set up tool settings (bottom bar)

        self.toolsettings[..] are the objects that hold min, max values for a given setting as
        as the current value (displayed as a slider and as a number).
        '''
        toolsettings_names = {
            "toolsettings_1", "toolsettings_2", "toolsettings_3"
        }
        self.toolsettings = {}

        for name in toolsettings_names:
            toolsettings = self.toolbar.findChild(QtWidgets.QWidget, name)
            toolsettings.connect_config(config)
            self.toolsettings[name] = toolsettings
        '''
        Set up data monitor/alarms (side bar) and plots

        self.monitors[..] are the objects that hold monitor values and thresholds for alarm min
        and max. The current value and optional stats for the monitored value (mean, max) are set
        here.
        '''
        # plot slot widget names
        self.plots = {}
        for name in config['plots']:
            plot = self.main.findChild(QtWidgets.QWidget, name)
            plot.setFixedHeight(130)
            self.data_filler.connect_plot(name, plot)
            self.plots[name] = plot

        # The monitored fields from the default_settings.yaml config file
        self.monitors = {}
        for name in config['monitors']:
            monitor = Monitor(name, config)
            self.monitors[name] = monitor
            self.data_filler.connect_monitor(monitor)

        # The alarms are from the default_settings.yaml config file
        # self.alarms = {}
        # for name in config['alarms']:
        #     alarm = GuiAlarm(name, config, self.monitors, self.alarm_h)
        #     self.alarms[name] = alarm
        self.gui_alarm = GuiAlarms(config, self.esp32, self.monitors)
        for m in self.monitors.values():
            m.connect_gui_alarm(self.gui_alarm)

        # Get displayed monitors
        self.monitors_slots = self.main.findChild(QtWidgets.QVBoxLayout,
                                                  "monitors_slots")
        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)

        # Connect the frozen plots
        # Requires building of an ordered array to associate the correct controls with the plot.
        active_plots = []
        for slotname in self.plots:
            active_plots.append(self.plots[slotname])
        self.cursor = Cursor(active_plots)
        self.frozen_bot.connect_workers(self.data_filler, active_plots,
                                        self.cursor)
        self.frozen_right.connect_workers(active_plots, self.cursor)
        '''
        Instantiate DataHandler, which will start a new
        thread to read data from the ESP32. We also connect
        the DataFiller to it, so the thread will pass the
        data directly to the DataFiller, which will
        then display them.
        '''
        self._data_h = DataHandler(config, self.esp32, self.data_filler,
                                   self.gui_alarm)

        self.specialbar.connect_datahandler_config_esp32(
            self._data_h, self.config, self.esp32)
        '''
        Connect settings button to Settings overlay.
        '''
        self.settings = Settings(self)
        self.toppane.insertWidget(self.toppane.count(), self.settings)
        '''
        Set up start/stop auto/min mode buttons.

        Connect each to their respective mode toggle functions.
        The StartStopWorker class takes care of starting and stopping a run
        '''

        self._start_stop_worker = StartStopWorker(self, self.config,
                                                  self.esp32,
                                                  self.button_startstop,
                                                  self.button_autoassist,
                                                  self.toolbar, self.settings)

        self.button_startstop.released.connect(
            self._start_stop_worker.toggle_start_stop)
        self.button_autoassist.released.connect(
            self._start_stop_worker.toggle_mode)
        self.gui_alarm.connect_workers(self._start_stop_worker)
        '''
        Instantiate ControllerStatus
        '''
        self._ctr_status = ControllerStatus(config, self.esp32, self.settings,
                                            self._start_stop_worker)

    def lock_screen(self):
        self.toppane.setDisabled(True)
        self.show_toolbar(locked_state=True)
        self.alarms_settings.set_enabled_state(False)

    def unlock_screen(self):
        self.toppane.setEnabled(True)
        self.show_toolbar(locked_state=False)
        self.alarms_settings.set_enabled_state(True)

    def handle_unlock(self):
        button = self.button_unlockscreen
        if button.isDown():
            if button._state == 0:
                button._state = 1
                button.setAutoRepeatInterval(50)
            else:
                self.show_numpadbar()
                button._state = 0
                button.setAutoRepeatInterval(self.unlockscreen_interval)

    def goto_new_patient(self):
        self.show_startup()

    def goto_resume_patient(self):
        self.settings.update_config(self.user_settings)

        self.show_startup()

    def goto_settings(self):
        self.show_settings()
        self.show_settingsbar()
        if self._start_stop_worker.mode == self._start_stop_worker.MODE_ASSIST:
            self.settings.tabs.setCurrentWidget(self.settings.tab_psv)
        elif self._start_stop_worker.mode == self._start_stop_worker.MODE_AUTO:
            self.settings.tabs.setCurrentWidget(self.settings.tab_pcv)

    def goto_main(self):
        self.show_main()
        self.show_toolbar()

    def exit_settings(self):
        self.show_main()
        self.show_menu()

    def goto_alarms(self):
        self.show_alarms()
        self.show_alarmsbar()
        self.alarms_settings.config_monitors()

    def exit_alarms(self):
        self.show_menu()
        self.show_plots()
        self.alarms_settings.deconfig_monitors()

    def show_settings(self):
        self.toppane.setCurrentWidget(self.settings)
        self.settings.tabs.setFocus()

    def show_startup(self):
        self.toppane.setCurrentWidget(self.startup)

    def show_menu(self):
        self.bottombar.setCurrentWidget(self.menu)

    def show_numpadbar(self):
        self.bottombar.setCurrentWidget(self.numpadbar)

    def show_toolbar(self, locked_state=False):
        """
        Shows the toolbar in the bottom bar.

        locked_state: If true, shows the unlock button. Otherwise shows the menu button.
        """
        self.bottombar.setCurrentWidget(self.toolbar)
        if locked_state:
            self.home_button.setCurrentWidget(self.goto_unlock)
        else:
            self.home_button.setCurrentWidget(self.goto_menu)

    def show_settingsbar(self):
        self.bottombar.setCurrentWidget(self.settingsbar)

    def show_specialbar(self):
        self.bottombar.setCurrentWidget(self.specialbar)

    def show_main(self):
        self.toppane.setCurrentWidget(self.main)

    def show_settingsfork(self):
        self.bottombar.setCurrentWidget(self.settingsfork)

    def show_alarms(self):
        self.centerpane.setCurrentWidget(self.alarms_settings)

    def show_plots(self):
        self.centerpane.setCurrentWidget(self.plots_all)

    def show_alarmsbar(self):
        self.bottombar.setCurrentWidget(self.alarmsbar)

    def freeze_plots(self):
        self.data_filler.freeze()
        self.rightbar.setCurrentWidget(self.frozen_right)
        self.bottombar.setCurrentWidget(self.frozen_bot)

    def unfreeze_plots(self):
        self.data_filler.unfreeze()
        self.rightbar.setCurrentWidget(self.monitors_bar)
        self.show_specialbar()
class MainWindow(QtWidgets.QMainWindow):
    """
    The class taking care for the main window.
    It is top-level with respect to other panes, menus, plots and
    monitors.
    """

    # this is a signal that sends fastdata from the mainloop to the slowloop
    request_from_slowloop = QtCore.pyqtSignal(object)
    request_to_update_cal = QtCore.pyqtSignal(object)
    update_vol_offset = QtCore.pyqtSignal(float)
    restart_looping_plot = QtCore.pyqtSignal()
    new_sensor_cal = QtCore.pyqtSignal(str)
    new_breath_data = QtCore.pyqtSignal(
        object)  #received new breath data from fastloop
    sensor_initialized = QtCore.pyqtSignal(
    )  # emits once the sensor has done its initial rezero process

    def __init__(self,
                 config,
                 main_path,
                 mode='normal',
                 diagnostic=False,
                 verbose=False,
                 simulation=False,
                 logdata=False,
                 *args,
                 **kwargs):
        """
        Initializes the main window
        """

        super(MainWindow, self).__init__(*args, **kwargs)
        uic.loadUi('mainwindow.ui', self)  # Load the .ui file

        # set mode
        if mode.lower() == 'debug':
            self.fast_update_time = 100
            self.fslow_update_time = 1000
            self.mode_verbose = True

        else:
            self.fast_update_time = 10
            self.slow_update_time = 1000
            self.mode_verbose = False

        # show full screen if running on a raspberry pi
        if 'raspberrypi' in os.uname():
            self.showFullScreen()

        # configuration
        self.config = config

        # data filler
        self.data_filler = data_filler.DataFiller(config=self.config)

        # run in verbose mode? do this if requested specifically or if running in debug mode
        self.verbose = (verbose) or (self.mode_verbose)

        # define the top level main path
        self.main_path = main_path
        if self.verbose:
            print(f"main: main path = {self.main_path}")

        # define the slow and fast data classes that hold the data generated by the loops
        self.time_to_display = 10  #seconds
        self.num_samples = int(self.time_to_display * 1000 /
                               self.fast_update_time)

        #hold an index about where in the plot (ie an index within num_samples) to put the next data
        self.index = 0

        self.fastdata = data_handler.fast_data()
        self.slowdata = data_handler.slow_data()
        self.breathdata = data_handler.breath_data()
        self.breathpar = data_handler.breath_par()

        # Start up the fast loop (data acquisition)
        self.fast_loop = data_handler.fast_loop(main_path=self.main_path,
                                                config=self.config,
                                                simulation=simulation,
                                                logdata=logdata,
                                                verbose=self.verbose)

        # once the sensor is initialized, start the fastloop
        self.sensor_initialized.connect(self.start_fastloop)
        while True:
            if self.fast_loop.sensor.initialized:
                self.sensor_initialized.emit()
                print(
                    'fastloop: sensor initialized. safe to start data acquisition: '
                )

                break

        # if the fastloop signals it has new data, grab it
        self.fast_loop.newdata.connect(self.update_fast_data)

        # start up the slow loop (calculations)
        self.slow_loop = data_handler.slow_loop(main_path=self.main_path,
                                                config=self.config,
                                                verbose=self.verbose)
        self.slow_loop.start()
        self.slow_loop.new_slowdata.connect(self.update_slow_data)
        #self.restart_looping_plot.connect(self.fast_loop.sensor.update_ambient_pressure)
        self.slow_loop.new_breathpar.connect(self.update_breath_params)
        # if the slowloop requests new data, send it the current fastdata
        self.slow_loop.request_fastdata.connect(self.slowloop_request)
        self.request_from_slowloop.connect(self.slow_loop.update_fast_data)

        # rezero the volume offset
        #self.update_vol_offset.connect(self.fast_loop.update_vol_offset)
        #self.update_vol_offset.connect(self.fast_loop.update_flow_trend)
        #self.update_vol_offset.connect(self.fast_loop.update_vol_trend)
        #self.update_vol_offset.connect(self.fast_loop.restart_integral)

        # if new breath detected tell fastloop to reset the integral
        #self.restart_looping_plot.connect(self.fast_loop.update_vol_trend)

        #if new breath data is received from fastloop, pass it to slowloop and ask for the breath params to be calculated
        self.new_breath_data.connect(self.slow_loop.calculate_breath_params)

        # if a new sensor calibration is selected, pass the new selection to fastdata.sensor
        self.new_sensor_cal.connect(self.fast_loop.sensor.set_mouthpiece)

        # if the fastloop sends new breath data, populate the mainloop breathdata
        self.fast_loop.new_breath.connect(self.update_breath_data)
        self.fast_loop.new_breath.connect(self.slow_loop.update_breath_data)

        # want to just show the plots to dewbug the calculations?
        self.diagnostic = diagnostic
        ### GUI stuff ###
        self.setWindowTitle("Open Respiratory Monitor")
        '''
        Get the toppane and child pages
        '''
        #self.toppane = self.findChild(QtWidgets.QStackedWidget, "toppane")
        self.main = self.findChild(QtWidgets.QWidget, "main")
        #self.initial = self.findChild(QtWidgets.QWidget, "initial")
        #self.startup = self.findChild(QtWidgets.QWidget, "startup")
        self.alarmbar = self.findChild(QtWidgets.QWidget, "alarmbar")
        self.toolbar = self.findChild(QtWidgets.QWidget, "toolbar")
        self.calpage = self.findChild(QtWidgets.QWidget, "calibration")
        self.statspage = self.findChild(QtWidgets.QWidget, "statspage")
        self.rezero_page = self.findChild(QtWidgets.QWidget, "rezero_page")
        '''
        Get the center pane (plots) widgets
        '''
        self.centerpane = self.findChild(QtWidgets.QStackedWidget,
                                         "centerpane")
        self.plots_all = self.findChild(QtWidgets.QWidget, "plots_all")
        self.plots_loops = self.centerpane.findChild(QtWidgets.QWidget,
                                                     "plots_loops")

        self.plots = {}
        for name in self.config['plots']:
            plot = self.main.findChild(QtWidgets.QWidget, name)
            self.data_filler.connect_plot(name, plot)
            self.plots[name] = plot

        # set up the loop plots
        self.plot_left = self.plots_loops.findChild(QtWidgets.QWidget,
                                                    "plot_left")
        self.plot_right = self.plots_loops.findChild(QtWidgets.QWidget,
                                                     "plot_right")

        labelStyle = {
            'color': self.config['axis_line_color'],
            'font-size': '18pt'
        }
        self.plot_left.setLabel(
            'left', self.config['monitors']['tidal_volume']['name'] + '' +
            self.config['monitors']['tidal_volume']['units'], **labelStyle)
        self.plot_left.setLabel(
            'bottom',
            'Pressure' + '' + self.config['monitors']['peep']['units'],
            **labelStyle)
        self.plot_right.setLabel(
            'left', self.config['monitors']['flow']['name'] + '' +
            self.config['monitors']['tidal_volume']['units'], **labelStyle)
        self.plot_right.setLabel(
            'bottom',
            'Pressure' + '' + self.config['monitors']['peep']['units'],
            **labelStyle)

        # Remove mouse interaction with plots
        self.plot_left.setMouseEnabled(x=False, y=False)
        self.plot_left.setMenuEnabled(False)
        self.plot_right.setMouseEnabled(x=False, y=False)
        self.plot_right.setMenuEnabled(False)

        yellow = pg.mkPen(color='y', width=2)
        pink = pg.mkPen(color='m', width=2)
        blue = pg.mkPen(color='b', width=2)
        green = pg.mkPen(color='g', width=2)

        # define the curves to plot
        self.line_left = self.plot_left.plot([0], [0], pen=yellow)
        self.line_right = self.plot_right.plot([0], [0], pen=blue)
        '''
        Get the alarm-related stuff
        '''
        self.alarms_settings = self.findChild(QtWidgets.QWidget,
                                              "alarms_settings")
        self.alarmsbar = self.findChild(QtWidgets.QWidget, "alarmsbar")
        '''
        Get the stackable bits on the right
        '''
        self.rightbar = self.main.findChild(QtWidgets.QStackedWidget,
                                            "rightbar")
        self.monitors_bar = self.main.findChild(QtWidgets.QWidget,
                                                "monitors_bar")
        self.frozen_right = self.main.findChild(QtWidgets.QWidget,
                                                "frozenplots_right")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")
        '''
        Get the bar at the bottom
        '''

        self.frozen_bot = self.findChild(QtWidgets.QWidget,
                                         "frozenplots_bottom")
        # Get frozen plots bottom bar widgets and connect
        self.button_unfreeze = self.frozen_bot.findChild(
            QtWidgets.QPushButton, "button_unfreeze")

        self.settingsfork = self.findChild(QtWidgets.QWidget,
                                           "settingsforkbar")
        self.button_alarms = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_alarms")
        self.button_arm = self.settingsfork.findChild(QtWidgets.QPushButton,
                                                      "button_arm")

        self.button_silence = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_silence")

        self.button_freeze = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_freeze")

        self.button_tools = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_tools")
        self.button_viewwaves = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_viewwaves")
        self.button_viewloops = self.settingsfork.findChild(
            QtWidgets.QPushButton, "button_viewloops")

        self.button_backalarms = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_backalarms")
        self.button_applyalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_applyalarm")
        self.button_resetalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_resetalarm")
        self.button_upalarm = self.alarmsbar.findChild(QtWidgets.QPushButton,
                                                       "button_upalarm")
        self.button_downalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_downalarm")
        self.button_offalarm = self.alarmsbar.findChild(
            QtWidgets.QPushButton, "button_offalarm")
        '''
        # stats bar
        '''
        self.statsbar = self.findChild(QtWidgets.QWidget, "statsbar")
        self.button_backstats = self.statsbar.findChild(
            QtWidgets.QPushButton, "button_back")
        self.button_tidal = self.statsbar.findChild(QtWidgets.QPushButton,
                                                    "button_tidal")
        self.button_peak = self.statsbar.findChild(QtWidgets.QPushButton,
                                                   "button_peak")
        self.button_peep = self.statsbar.findChild(QtWidgets.QPushButton,
                                                   "button_peep")

        self.button_resetstats = self.statspage.findChild(
            QtWidgets.QPushButton, "button_resetstats")
        '''
        stats page
        '''
        self.stats_name = self.statspage.findChild(QtWidgets.QLabel,
                                                   "name_parameter")
        self.stats_mean = self.statspage.findChild(QtWidgets.QLabel,
                                                   "num_mean")
        self.stats_min = self.statspage.findChild(QtWidgets.QLabel, "num_min")
        self.stats_max = self.statspage.findChild(QtWidgets.QLabel, "num_max")
        self.stats_pcterr = self.statspage.findChild(QtWidgets.QLabel,
                                                     "num_pcterror")
        self.stats_stderr = self.statspage.findChild(QtWidgets.QLabel,
                                                     "num_stderror")
        self.stats_units = self.statspage.findChild(QtWidgets.QLabel,
                                                    "num_units")
        self.statplot = self.statspage.findChild(QtWidgets.QWidget,
                                                 "plot_stats")
        self.button_resetstats = self.statspage.findChild(
            QtWidgets.QPushButton, "button_resetstats")

        # make the plot
        pen = pg.mkPen(color='y', width=2)
        pen = pg.mkPen(None)
        self.statline = self.statplot.plot([0], [0],
                                           pen=pen,
                                           symbol='o',
                                           symbolSize=20,
                                           symbolBrush=('y'))

        # set up the statistics set which will hold useful statistics about the breaths
        self.statset = Statset()
        for name in self.config['statistics']:
            self.statset.add_stat(name)
            #print("found statistic: ",name)
        # set the current stat that will be shown (by default its the first one in the config)
        self.current_stat = self.config['statistics'][0]
        print('mainloop: current stat = ', self.current_stat)
        self.set_displayed_stat(self.current_stat)
        '''
        # toolbar buttons
        '''

        self.button_backsettings = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_back")

        self.button_calsettings = self.toolbar.findChild(
            QtWidgets.QPushButton, "button_calsettings")

        self.button_hamilton = self.calpage.findChild(QtWidgets.QPushButton,
                                                      "button_hamilton")
        self.button_iqspiro = self.calpage.findChild(QtWidgets.QPushButton,
                                                     "button_iqspiro")

        self.button_stats = self.toolbar.findChild(QtWidgets.QPushButton,
                                                   "button_stats")

        self.button_rezero = self.calpage.findChild(QtWidgets.QPushButton,
                                                    "button_rezero")
        self.button_rezero_yes = self.rezero_page.findChild(
            QtWidgets.QPushButton, "button_rezero_yes")
        self.button_rezero_no = self.rezero_page.findChild(
            QtWidgets.QPushButton, "button_rezero_no")
        self.num_p1 = self.rezero_page.findChild(QtWidgets.QLabel, "num_p1")
        self.num_p2 = self.rezero_page.findChild(QtWidgets.QLabel, "num_p2")
        '''
        Frozen Plot menu
        '''

        # Connect the frozen plots
        # Requires building of an ordered array to associate the correct
        # controls with the plot.
        active_plots = []
        for slotname in self.plots:
            active_plots.append(self.plots[slotname])
        self.cursor = Cursor(active_plots)
        self.frozen_bot.connect_workers(self.data_filler, active_plots,
                                        self.cursor)
        self.frozen_right.connect_workers(active_plots, self.cursor)

        # Frozen Plots
        self.button_freeze.pressed.connect(self.freeze_plots)
        self.button_unfreeze.pressed.connect(self.unfreeze_plots)
        '''
        Define the monitors
        '''

        # The monitored fields from the default_settings.yaml config file
        self.monitors = {}
        for name in config['monitors']:
            monitor = Monitor(name, config)
            self.monitors[name] = monitor
            self.data_filler.connect_monitor(monitor)
        # Get displayed monitors
        self.monitors_slots = self.main.findChild(QtWidgets.QVBoxLayout,
                                                  "monitors_slots")
        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)
        '''
        Start the alarm handler, which will check for ESP alarms
        '''
        self.alarm_h = AlarmHandler(self.config, self.alarmbar)

        # The alarms are from the default_settings.yaml config file
        # self.alarms = {}
        # for name in config['alarms']:
        #     alarm = GuiAlarm(name, config, self.monitors, self.alarm_h)
        #     self.alarms[name] = alarm
        self.gui_alarm = GuiAlarms(config, self.monitors)

        print('trying to connect alarms')
        for monitor in self.monitors.values():
            monitor.connect_gui_alarm(self.gui_alarm)
        '''
        Connect the menu buttons to actions
        '''
        self.button_alarms.pressed.connect(self.goto_alarms)

        self.alarms_settings.connect_monitors(self)
        self.alarms_settings.populate_monitors()
        self.button_applyalarm.pressed.connect(
            self.alarms_settings.apply_selected)
        self.button_resetalarm.pressed.connect(
            self.alarms_settings.reset_selected)
        self.button_offalarm.pressed.connect(
            self.alarms_settings.move_selected_off)
        self.button_upalarm.pressed.connect(
            self.alarms_settings.move_selected_up)
        self.button_downalarm.pressed.connect(
            self.alarms_settings.move_selected_down)
        self.button_backalarms.pressed.connect(self.exit_alarms)

        self.button_viewloops.pressed.connect(self.show_loops)
        self.button_viewwaves.pressed.connect(self.show_waveforms)

        #self.button_zero_flow.pressed.connect(self.zero_sensor_flow)

        # toolbar
        self.button_tools.pressed.connect(self.show_toolbar)
        self.button_backsettings.pressed.connect(self.exit_alarms)
        self.button_calsettings.pressed.connect(self.goto_calsettings)
        self.button_stats.pressed.connect(self.goto_stats)
        self.button_backstats.pressed.connect(self.show_toolbar)

        # calibration selection
        self.button_hamilton.toggled.connect(self.togglecal_hamilton)
        self.button_iqspiro.toggled.connect(self.togglecal_iqspiro)
        self.button_rezero.pressed.connect(self.goto_rezero_page)
        self.button_rezero_yes.pressed.connect(self.rezero_sensor)
        self.button_rezero_no.pressed.connect(self.goto_calsettings)
        self.button_rezero_no.pressed.connect(self.show_toolbar)

        # stats page
        self.button_tidal.pressed.connect(
            lambda: self.set_displayed_stat('tidal_volume'))
        self.button_peak.pressed.connect(
            lambda: self.set_displayed_stat('peak'))
        self.button_peep.pressed.connect(
            lambda: self.set_displayed_stat('peep'))
        self.button_resetstats.pressed.connect(self.reset_stats)
        ''' 
        arming the alarms
        '''
        self.button_arm.toggled.connect(self.arm_disarm_alarms)
        # set up the mute audio alarm buttion
        self.button_silence.pressed.connect(self.silence_alarms)

        # Show the Page
        self.goto_main()
        self.show_settingsfork()

        ### Stuff from the original just plots gui ###
        if self.diagnostic:
            self.graph0 = pg.PlotWidget()
            self.graph1 = pg.PlotWidget()
            self.graph2 = pg.PlotWidget()
            self.graph3 = pg.PlotWidget()

            layout = QtWidgets.QVBoxLayout()
            layout.addWidget(self.graph0)
            layout.addWidget(self.graph1)
            layout.addWidget(self.graph2)
            layout.addWidget(self.graph3)

            widget = QtWidgets.QWidget()
            widget.setLayout(layout)

            # make the window with a graph widget
            self.setCentralWidget(widget)

            # set the plot properties
            self.graph0.setBackground('k')
            self.graph0.showGrid(x=True, y=True)
            self.graph1.setBackground('k')
            self.graph1.showGrid(x=True, y=True)
            self.graph2.setBackground('k')
            self.graph2.showGrid(x=True, y=True)
            self.graph3.setBackground('k')
            self.graph3.showGrid(x=True, y=True)

            # Set the label properties with valid CSS commands -- https://groups.google.com/forum/#!topic/pyqtgraph/jS1Ju8R6PXk
            labelStyle = {'color': '#FFF', 'font-size': '12pt'}
            self.graph0.setLabel('left', 'Inspiring', 'cmH20', **labelStyle)
            self.graph1.setLabel('left', 'Flow ', 'L/m', **labelStyle)
            self.graph2.setLabel('left', 'Flow Slope', 'L/m/s', **labelStyle)
            self.graph3.setLabel('left', 'V', 'mL', **labelStyle)
            self.graph3.setLabel('bottom', 'Time', 's', **labelStyle)

            # change the plot range
            #self.graph1.setYRange(-10,40,padding = 0.1)
            #self.graph2.setYRange(-100,100,padding = 0.1)
            #self.graph3.setYRange(0,750,padding = 0.1)

            # make a QPen object to hold the marker properties
            yellow = pg.mkPen(color='y', width=2)
            pink = pg.mkPen(color='m', width=2)
            blue = pg.mkPen(color='b', width=2)
            green = pg.mkPen(color='g', width=2)

            # define the curves to plot
            self.data_line0 = self.graph0.plot(self.fastdata.dt,
                                               self.fastdata.p1,
                                               pen=yellow)
            self.data_line1 = self.graph1.plot(self.fastdata.dt,
                                               self.fastdata.flow,
                                               pen=blue)
            #self.data_line1b = self.graph1.plot(self.fastdata.dt,   self.fastdata.p2, pen = bluepen)
            self.data_line2 = self.graph2.plot(self.fastdata.dt,
                                               self.fastdata.dflow,
                                               pen=pink)
            self.data_line3 = self.graph3.plot(self.fastdata.dt,
                                               self.fastdata.vol * 1000,
                                               pen=green)

        # update the graphs at regular intervals (so it runs in a separate thread!!)
        # Stuff with the timer
        self.t_update = self.config[
            'plot_interval']  #self.fast_update_time*5 #update time of timer in ms
        self.timer = QtCore.QTimer()
        self.timer.setInterval(self.t_update)
        self.timer.timeout.connect(self.update_plots)
        self.timer.start()

    ###  gui-related functions ###

    def show_waveforms(self):
        self.centerpane.setCurrentWidget(self.plots_all)

    def show_loops(self):
        self.centerpane.setCurrentWidget(self.plots_loops)

    def lock_screen(self):
        """
        Perform screen locking.
        """

        self.toppane.setDisabled(True)
        #self.show_toolbar(locked_state=True)
        self.alarms_settings.set_enabled_state(False)

    def unlock_screen(self):
        """
        Perform screen unlocking.
        """

        self.toppane.setEnabled(True)
        #self.show_toolbar(locked_state=False)
        self.alarms_settings.set_enabled_state(True)

    def handle_unlock(self):
        """
        Handle the screen unlock procedure.
        """

        button = self.button_unlockscreen
        if button.isDown():
            if button._state == 0:
                button._state = 1
                button.setAutoRepeatInterval(50)
            else:
                self.show_numpadbar()
                button._state = 0
                button.setAutoRepeatInterval(self.unlockscreen_interval)

    def goto_new_patient(self):
        """
        Go ahead with shallow set of operational parameters.
        """

        self.show_startup()

    def goto_resume_patient(self):
        """
        Go ahead with previously used operational parameters.
        """

        self.settings.update_config(self.user_settings)

        self.show_startup()

    def goto_stats(self):
        """
        open up the statistics page
        """
        self.toppane.setCurrentWidget(self.statspage)
        self.show_statsbar()

    def goto_rezero_page(self):
        """
        open up the statistics page
        """
        self.toppane.setCurrentWidget(self.rezero_page)
        self.show_toolbar()

    def show_statsbar(self):
        self.bottombar.setCurrentWidget(self.statsbar)

    def goto_calsettings(self):
        """
        open the calibration settings pane

        """
        self.check_sensor_cal()
        self.toppane.setCurrentWidget(self.calpage)
        self.show_toolbar()
        #self.calpage.tabs.setFocus()

    def togglecal_hamilton(self):
        """
        toggles the calibration when you click iqspiro
        """

        if self.button_hamilton.isChecked():
            self.button_iqspiro.setChecked(False)
        elif not (self.button_hamilton.isChecked()):
            self.button_iqspiro.setChecked(True)

        self.update_sensor_cal()

    def togglecal_iqspiro(self):
        """
        toggles the calibration when you click iqspiro
        """

        if self.button_iqspiro.isChecked():
            self.button_hamilton.setChecked(False)
        elif not (self.button_iqspiro.isChecked()):
            self.button_hamilton.setChecked(True)

        self.update_sensor_cal()

    def update_sensor_cal(self):
        """
        updates the calibration ie mouthpiece selection of the sensor
        """
        if self.button_iqspiro.isChecked():
            self.new_sensor_cal.emit('iqspiro')

        else:
            self.new_sensor_cal.emit('hamilton')

    def check_sensor_cal(self):
        """
        checks the current sensor cal to decide which box to check in the menu
        """
        print("mainloop: mouthpiece = ", self.fast_loop.sensor.mouthpiece)
        if self.fast_loop.sensor.mouthpiece == 'hamilton':
            self.button_hamilton.setChecked(True)
            self.button_iqspiro.setChecked(False)
        elif self.fast_loop.sensor.mouthpiece == 'iqspiro':
            self.button_hamilton.setChecked(False)
            self.button_iqspiro.setChecked(True)

    def goto_settings(self):
        """
        Open the Settings pane.
        """

        self.show_settings()
        self.show_settingsbar()
        if self._start_stop_worker.mode() == self._start_stop_worker.MODE_PSV:
            self.settings.tabs.setCurrentWidget(self.settings.tab_psv)
        elif self._start_stop_worker.mode(
        ) == self._start_stop_worker.MODE_PCV:
            self.settings.tabs.setCurrentWidget(self.settings.tab_pcv)

    def goto_main(self):
        """
        Open the home ui
        """

        self.show_main()
        #self.show_toolbar()

    def exit_settings(self):
        """
        Go back to home ui from the Settings pane.
        """

        self.show_main()
        self.show_menu()

    def goto_alarms(self):
        """
        Open the alarms settings pane.
        """

        self.show_alarms()
        self.show_alarmsbar()
        self.alarms_settings.config_monitors()

    def exit_alarms(self):
        """
        Go back to home ui from the alarms settings pane.
        """

        self.show_main()
        self.show_plots()
        self.show_settingsfork()
        self.alarms_settings.deconfig_monitors()

    def show_settings(self):
        """
        Open the Settings pane.
        """

        self.toppane.setCurrentWidget(self.settings)
        self.settings.tabs.setFocus()

    def show_startup(self):
        """
        Show the startup pane.
        """

        self.toppane.setCurrentWidget(self.startup)

    def show_menu(self):
        """
        Open the menu on the bottom of the home pane.
        """

        self.bottombar.setCurrentWidget(self.menu)

    def show_numpadbar(self):
        """
        Shows the numeric pad in the bottom of the home pane.
        """
        self.bottombar.setCurrentWidget(self.numpadbar)

    def show_toolbar(self, locked_state=False):
        """
        Shows the toolbar in the bottom bar.

        arguments:
        - locked_state: If true, shows the unlock button. Otherwise
                        shows the menu button.
        """
        self.bottombar.setCurrentWidget(self.toolbar)
        """
        if locked_state:
            self.home_button.setCurrentWidget(self.goto_unlock)
        else:
            self.home_button.setCurrentWidget(self.goto_menu)
        """

    def show_settingsbar(self):
        """
        Open the settings submenu.
        """

        self.bottombar.setCurrentWidget(self.settingsbar)

    def show_specialbar(self):
        """
        Open the special operations submenu.
        """

        self.bottombar.setCurrentWidget(self.specialbar)

    def show_main(self):
        """
        Show the home pane.
        """

        self.toppane.setCurrentWidget(self.main)
        self.show_waveforms()

    def show_settingsfork(self):
        """
        Show the intermediate settings submenu
        """

        self.bottombar.setCurrentWidget(self.settingsfork)

    def show_alarms(self):
        """
        Shows the alarm settings controls in the center of the alarm
        settings pane.
        """

        self.centerpane.setCurrentWidget(self.alarms_settings)

    def show_plots(self):
        """
        Shows the plots in the center of the home pane.
        """

        self.centerpane.setCurrentWidget(self.plots_all)

    def show_alarmsbar(self):
        """
        Shows the alarm settings controls in the bottom of the alarm
        settings pane.
        """

        self.bottombar.setCurrentWidget(self.alarmsbar)

    def freeze_plots(self):
        """
        Open the frozen plots pane.
        """

        self.data_filler.freeze()
        self.rightbar.setCurrentWidget(self.frozen_right)
        self.bottombar.setCurrentWidget(self.frozen_bot)

    def unfreeze_plots(self):
        """
        Go back to the home pane from the frozen plots pane.
        """

        self.data_filler.unfreeze()
        self.rightbar.setCurrentWidget(self.monitors_bar)
        self.show_main()
        self.show_settingsfork()

    ### gui-related functions
    def arm_disarm_alarms(self):
        if self.button_arm.isChecked():
            self.gui_alarm.arm_alarms()
            self.button_arm.setText('DISARM \nAlarms')
            self.button_arm.setStyleSheet('QPushButton {color: red;}')
            print('main: ARMED BUTTON CHECKED')
        elif not self.button_arm.isChecked():
            self.gui_alarm.disarm_alarms()
            print('main: ARMED BUTTON UNCHECKED')
            self.button_arm.setText('ARM \nAlarms')
            self.button_arm.setStyleSheet('QPushButton {color: green;}')

    def set_displayed_stat(self, name):
        # set the currently display stats in the statspage
        self.current_stat = name
        print('mainloop: current stat = ', self.current_stat)
        self.update_displayed_stats()

    def silence_alarms(self):
        self.gui_alarm.silence_alarms()

    def update_plots(self):

        # update the plots with the new data
        if self.diagnostic:
            self.data_line0.setData(self.fastdata.dt, self.fastdata.insp)
            #self.data_line1b.setData(self.fastdata.dt,   self.fastdata.p2)
            self.data_line1.setData(self.fastdata.dt, self.fastdata.flow)
            self.data_line2.setData(self.fastdata.dt,
                                    self.fastdata.dflow)  #flow)
            self.data_line3.setData(self.fastdata.dt,
                                    self.fastdata.vol * 1000)  #update the data

        #
        else:
            # add the data to the plot vectors
            for key in self.fastdata.all_fields.keys():
                self.data_filler.add_data_point(key,
                                                self.fastdata.all_fields[key])

            # update the plots
            #self.data_filler.update_all_plots()
            self.data_filler.update_plot('pressure')
            self.data_filler.update_plot('flow')
            self.data_filler.update_plot('volume')

            #check if the looping is restarting
            if self.data_filler._looping_restart:
                if True:
                    print('main: restarting loop on plots')
                #self.update_vol_offset.emit(self.slowdata.t_last)
                self.restart_looping_plot.emit()

    def update_monitors(self):
        """
        displayed_monitors:
        - peak
        - peep
        - minute_volume_measured
        - tidal_volume
        - respiratory_rate
        - i_to_e_ratio
        - cstat 
        - apnea_time
        - battery_low
        - battery_charging

        self.monitor_mapping = {'peak' : self.slowdata.pip,
                       'peep' : self.slowdata.peep,
                       'minute_volume_measured' : self.slowdata.mve_meas,
                       'tidal_volume' : self.slowdata.vt,
                       'respiratory_rate': self.slowdata.rr,
                       'i_to_e_ratio' : self.slowdata.ie,
                       'cstat' : self.slowdata.c,
                       'apnea_time' : self.slowdata.dt_last,
                       'battery_low': self.slowdata.lowbatt,
                       'battery_charging' : self.slowdata.battery_charging}


        """

        # define the mapping between monitor names and data points
        self.monitor_mapping = {
            'peak': self.breathpar.pip,
            'peep': self.breathpar.peep,
            'minute_volume_measured': self.slowdata.mve_meas,
            'tidal_volume': self.breathpar.vt,
            'respiratory_rate': self.breathpar.rr,
            'i_to_e_ratio': self.breathpar.ie,
            'cstat': self.breathpar.c,
            'apnea_time': self.slowdata.dt_last,
            'battery_low': self.slowdata.lowbatt,
            'battery_charging': self.slowdata.charging
        }

        for key in self.monitor_mapping.keys():
            try:
                value = self.monitor_mapping[key]
                if self.verbose:
                    print(f'main: adding to {key}: {value}')
                self.data_filler.add_data_point(key, value)
                self.data_filler.update_all_monitors()
            except Exception as e:
                #print(f'main: could not update monitor {key}: ',e)
                pass

        # update the p1 and p2 values in the rezero plot
        self.num_p1.setText('%0.3f' % self.fastdata.p1[-1])
        self.num_p2.setText('%0.3f' % self.fastdata.p2[-1])

        # check for alarms
        """
        self.gui_alarm = GuiAlarms(config, self.monitors)

        print('trying to connect alarms')
        for monitor in self.monitors.values():
            monitor.connect_gui_alarm(self.gui_alarm)
        """

        try:
            self.gui_alarm.set_data(self.monitor_mapping)
        except Exception as e:
            print('main: could not send data to guialarm: ', e)

    def update_loop_plots(self):
        self.line_left.setData(self.breathdata.p, self.breathdata.vol)
        self.line_right.setData(self.breathdata.p, self.breathdata.flow)

        # set the axis ranges
        pmax = np.max(self.breathdata.p)
        vmax = np.max(self.breathdata.vol)
        flowmax = np.max(np.abs(self.breathdata.flow))

        if pmax > 40:
            pmax_plot = pmax
        else:
            pmax_plot = 40

        if vmax > 1000:
            vmax_plot = vmax
        else:
            vmax_plot = 1000

        if flowmax > 75:
            flowmax_plot = flowmax
        else:
            flowmax_plot = 75

        # left plot (vol vs pressure)
        self.plot_left.setXRange(-5, pmax_plot)
        self.plot_left.setYRange(0, vmax_plot)

        # right plot (flow vs pressure)
        self.plot_right.setXRange(-5, pmax_plot)
        self.plot_right.setYRange(-flowmax_plot, flowmax_plot)

    ### slots to handle data transfer between threads ###

    def reset_stats(self):
        print('main: trying to reset stats')
        #clear out the data in the stats
        self.statset.reset_all()
        self.update_displayed_stats()

    def update_displayed_stats(self):

        # sends the stats for the selected statistic to the monitor
        stat = self.statset.stats[self.current_stat]
        name = self.config['monitors'][self.current_stat]['name']
        self.stats_name.setText(name)
        self.stats_mean.setText('%0.2f' % stat.mean)
        self.stats_min.setText('%0.2f' % stat.min)
        self.stats_max.setText('%0.2f' % stat.max)
        self.stats_pcterr.setText('%0.2f' % stat.pcterr)
        self.stats_stderr.setText('%0.2f' % stat.stderr)
        units = self.config['monitors'][self.current_stat]['units']
        self.stats_units.setText(units)

        labelStyle = {
            'color': self.config['axis_line_color'],
            'font-size': '18pt'
        }
        self.statplot.setLabel('left', name, units, **labelStyle)
        self.statplot.setLabel('bottom', 'Sample ', '', **labelStyle)
        self.statline.setData(np.arange(len(stat.data)), stat.data)
        self.statplot.enableAutoRange(axis='y', enable=True)

    def update_breath_data(self, data):
        # gets the new breath data from the fast loop
        if self.verbose:
            print("main: received new breath data from fastloop")
        self.breathdata = data
        #print(f'main: self.breathdata.tsi = {self.breathdata.tsi}')
        #print(f'main: self.breathdata.tei = {self.breathdata.tei}')
        #print(f'main: self.breathdata.tee = {self.breathdata.tee}')
        self.update_loop_plots()
        self.new_breath_data.emit(self.breathdata)

    def update_breath_params(self, data):
        # gets the new breath parameters calculated by the slow loop
        if self.verbose:
            print("main: received new breath parameters from slowloop")
        self.breathpar = data
        print(f"main: peep = {self.breathpar.peep}")
        self.update_monitors()

        # add the new data for the tracked statistics
        for name in self.config['statistics']:
            try:
                datapoint = self.monitor_mapping[name]
                if True:  #self.verbose:
                    print(f'adding  to statistics for {name}: {datapoint}')
                self.statset.add_data_point(name, datapoint)
            except Exception as e:
                print(f'main: could not update statistics for {name}', e)
        self.update_displayed_stats()

    def update_fast_data(self, data):
        if self.verbose:
            print("main: received new data from fastloop!")

        self.fastdata = data
        #self.update_plots()

    #def reset_volume_offset(self):
    #self.fastloop.

    def rezero_sensor(self):
        '''
        Set the current pressure and flow to zero
        '''
        self.fast_loop.sensor.rezero()
        #self.goto_calsettings()

    def update_slow_data(self, data):
        if True:  #self.verbose:
            print("main: received new data from slowloop!")
        self.slowdata = data
        print(f"main: slowloop data: dt_last = {self.slowdata.dt_last}")
        self.update_monitors()
        #os.system('cls' if os.name == 'nt' else 'clear')
        #data.print_data()

    def slowloop_request(self):
        if self.verbose:
            print(f"main: received request for data from slowloop")
        self.request_from_slowloop.emit(self.fastdata)

    def start_fastloop(self):
        """
        Starts up the data acquisition fast loop
        """
        print('main: starting fastloop')
        self.fast_loop.start()