Beispiel #1
0
def excepthook(excection_type, excection_value, traceback_object):
    """Callback for any unhandled exceptions in the main thread. To use set sys.excepthook = excepthook"""
    separator = '-' * 50
    body_text = "Oh no! Part of the program has crashed. If you had a session active don't worry it will be saved when the program closes.\n" \
                "Please report this error on the github issue tracker.\nPress Ctrl+C to copy text from this dialog."
    current_time = time.strftime("%Y-%m-%d, %H:%M:%S")
    version_info = "DySense Version {}".format(app_version)

    # Get useful information from traceback object
    traceback_file = cStringIO.StringIO()
    traceback.print_tb(traceback_object, None, traceback_file)
    traceback_file.seek(0)
    traceback_info = traceback_file.read()

    error_message = '{}: \n{}'.format(excection_type, make_unicode(excection_value))
    sections = [body_text, separator, version_info, current_time, separator,
                error_message, separator, traceback_info]
    unicode_sections = [make_unicode(s) for s in sections]
    dialog_message = '\n'.join(unicode_sections)

    popup = QtGui.QMessageBox()
    popup.setText(dialog_message)
    popup.setWindowTitle('Error')
    popup.setWindowIcon(popup.style().standardIcon(QStyle.SP_MessageBoxCritical))
    popup.exec_()

    # This will cause app.exec_() to return.
    QtCore.QCoreApplication.exit(1)
Beispiel #2
0
 def sensor_type_selected(self):
     self.sensor_name_line_edit.setFocus()
     try:
         sensor_id_type = self.possible_sensor_id_types[
             self.sensor_type_combo_box.currentIndex()]
         self.sensor_id_type_label.setText('{} - '.format(
             make_unicode(sensor_id_type)))
         self.selected_id_type = make_unicode(sensor_id_type)
     except IndexError:
         pass
Beispiel #3
0
    def handle_new_message(self, id, instance, body):

        if id == GlobID.AssertMessage:
            msg = AssertMessage.from_bytes(body)
            if msg.valid:
                self.send_text('ASSERT:' + make_unicode(msg.message))

        elif id == GlobID.DebugMessage:
            msg = DebugMessage.from_bytes(body)
            if msg.valid:
                self.send_text('DEBUG:' + make_unicode(msg.message))

        elif id == GlobID.UserData:
            msg = UserData.from_bytes(body)

            self.handle_data(self.utc_time, self.sys_time, (msg.roll, msg.pitch, msg.yaw, msg.battery))
Beispiel #4
0
    def refresh_sensor_data(self, sensor_id, new_set_of_data):

        row_index = self.sensor_id_to_row_index[sensor_id]
        data_info = self.sensor_id_to_data_info[sensor_id]

        for i, data_value in enumerate(new_set_of_data):

            # Add one since first column is sensor name.
            column_index = i + 1

            table_item = self.data_table.item(row_index, column_index)
            if table_item is None:
                continue  # set of data is larger than expected

            if isinstance(data_value, float):
                try:
                    desired_decimal_places = data_info[i]['decimal_places']
                    data_value = format_decimal_places(data_value,
                                                       desired_decimal_places)
                except KeyError:
                    # Number of decimals not specified so limit at 5.
                    data_value = limit_decimal_places(data_value, 5)

            table_item.setText(make_unicode(data_value))

        if not self.sensor_id_to_data_status[sensor_id]:
            # First time showing data for this sensor show make sure columns are big enough to show it.
            self.data_table.resizeColumnsToContents()
        else:
            # Remember that we've shown data for this sensor because constantly resizing looks funny.
            self.sensor_id_to_data_status[sensor_id] = True
    def closeEvent(self, *args, **kwargs):

        notes = make_unicode(self.session_notes.toPlainText()).strip()

        self.controller_view.update_session_notes(notes)

        return QDialog.closeEvent(self, *args, **kwargs)
    def update_info(self, controller_info):

        self.controller_info = controller_info

        # Treat controller ID as a setting.
        self.settings_widget.update_setting('id', controller_info['id'])

        session_state = controller_info['session_state']
        if session_state.lower() == 'closed':
            session_status = 'Not Started'
        else:
            session_status = session_state
        self.session_status_label.setText(make_unicode(pretty(session_status)))

        settings = controller_info['settings']
        for setting_name, setting_value in settings.iteritems():
            self.settings_widget.update_setting(setting_name, setting_value)
            if self.end_session_dialog is not None and self.end_session_dialog.isVisible(
            ):
                self.end_session_dialog.update_controller_setting(
                    setting_name, setting_value)

        extra_settings = controller_info['extra_settings']
        for setting_name, setting_value in extra_settings.iteritems():
            self.settings_widget.update_setting(setting_name, setting_value)
            if self.end_session_dialog is not None and self.end_session_dialog.isVisible(
            ):
                self.end_session_dialog.update_controller_setting(
                    setting_name, setting_value)
Beispiel #7
0
    def show_user_message(self, message, level):

        popup = QtGui.QMessageBox()
        font = QtGui.QFont()
        font.setPointSize(13)
        popup.setFont(font)

        if level == logging.CRITICAL:
            level_text = "Critical Error"
            icon = QStyle.SP_MessageBoxCritical
        elif level == logging.ERROR:
            level_text = "Error"
            icon = QStyle.SP_MessageBoxWarning
        elif level == logging.WARN:
            level_text = "Warning"
            icon = QStyle.SP_MessageBoxWarning
        elif level == logging.INFO:
            level_text = "Info"
            icon = QStyle.SP_MessageBoxInformation
        else:
            return  # not a level we need to show

        popup.setText(make_unicode(message))
        popup.setWindowTitle('{}'.format(level_text))
        popup.setWindowIcon(popup.style().standardIcon(icon))

        popup.exec_()
    def confirm_button_clicked(self):

        notes = make_unicode(self.session_notes.toPlainText()).strip()

        self.presenter.send_controller_command('stop_session',
                                               notes,
                                               send_to_all_controllers=False)

        self.close()
Beispiel #9
0
    def __init__(self, sensor_id, instrument_id, settings, context,
                 connect_endpoint):
        '''
        Constructor. Save properties for opening serial port later.

        Args:
            sensor_id - unique ID assigned by the program.
            settings - dictionary of sensor settings. Must include:
                port - serial port name (e.g. 'COM20')
                baud - serial port rate in bits per second.
                message_rate - how fast GPS is setup to output messages (Hz)
            context - ZMQ context instance.
            connect_endpoint - endpoint on local host to receive time/commands from.

        Raises:
            ValueError - if not all settings are provided or not in correct format.
        '''
        try:
            self.port = make_unicode(settings['port'])
            self.baud = int(settings['baud'])
            self.message_period = 1.0 / float(settings['message_rate'])
            self.required_fix = make_unicode(settings['required_fix'])
            self.required_latlon_error = float(settings['required_error'])
            self.min_sats = int(settings['min_sats'])
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(e))

        GpsNmea.__init__(self,
                         self.required_fix,
                         self.required_latlon_error,
                         self.min_sats,
                         sensor_id=sensor_id,
                         instrument_id=instrument_id,
                         context=context,
                         connect_endpoint=connect_endpoint,
                         throttle_sensor_read=False)

        # Set base class fields.
        self.desired_read_period = self.message_period + 1
        self.max_closing_time = 3  # seconds

        # Serial port connection.
        self.connection = None
Beispiel #10
0
    def __init__(self, sensor_id, instrument_id, settings, context,
                 connect_endpoint):
        '''
        Constructor. Save properties for opening serial port later.

        Args:
            sensor_id - unique ID assigned by the program.
            settings - dictionary of sensor settings. Must include:
                port - serial port name (e.g. 'COM20')
                baud - serial port rate in bits per second.
                output_period - how fast microcontroller is setup to output data (seconds)
                default_reading - distance that sensor returns when it's not getting a valid return.
                timeout_duration - how long that 'default_reading' has to be received before reporting an error.
            context - ZMQ context instance.
            connect_endpoint - endpoint on local host to receive time/commands from.

        Raises:
            ValueError - if not all settings are provided or not in correct format.
        '''
        SensorBase.__init__(self,
                            sensor_id,
                            instrument_id,
                            context,
                            connect_endpoint,
                            throttle_sensor_read=False)

        try:
            self.port = make_unicode(settings['port'])
            self.baud = int(settings['baud'])
            self.output_period = float(settings['output_period'])
            self.default_reading = float(settings['default_reading'])
            self.timeout_duration = float(settings['timeout_duration'])
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(e))

        # Set base class fields.  Set desired read period to be higher since MCU doesn't report at a constant rate.
        # This works because the throttle sensor read is disabled.
        self.desired_read_period = self.output_period + 1
        self.max_closing_time = 3  # seconds

        # Serial port connection.
        self.connection = None

        # Buffer of bytes that haven't been converted into a distance yet.
        self.byte_buffer = []

        # State of monitoring timeout based on constant data readings.
        if self.timeout_duration <= 0:
            self.monitor_state = 'disabled'
        else:
            self.monitor_state = 'ok'

        # How long that 'default_reading' has been received without getting another value.
        self.default_reading_elapsed = 0
Beispiel #11
0
    def local_controller_name(self):
        stored_controller_name = self.qt_settings.value(
            "local_controller_name")
        if stored_controller_name is None:
            stored_controller_name = "default"

        # Make it so the first name returned is always the name returned to prevent
        # the controller name from changing as the program is running.
        if self.initial_stored_controller_name is None:
            self.initial_stored_controller_name = stored_controller_name

        return make_unicode(self.initial_stored_controller_name)
Beispiel #12
0
    def confirm_question(self, question, title='Question'):

        popup = QtGui.QMessageBox()
        popup.setFont(QtGui.QFont('popup_font', pointSize=14))
        popup.setText(make_unicode(question))
        popup.setWindowTitle(title)
        popup.setWindowIcon(popup.style().standardIcon(
            QStyle.SP_MessageBoxQuestion))
        popup.setStandardButtons(QMessageBox.No | QMessageBox.Yes)

        reply = popup.exec_()
        return reply == QtGui.QMessageBox.Yes
Beispiel #13
0
    def __init__(self, sensor_id, instrument_id, settings, context,
                 connect_endpoint):

        try:
            self.test_file_path = os.path.abspath(
                make_unicode(settings['test_file_path']).strip('"'))
            self.output_rate = make_unicode(settings['output_rate'])
            self.required_fix = make_unicode(settings['required_fix'])
            self.required_latlon_error = float(settings['required_error'])
            self.min_sats = int(settings['min_sats'])
            self.output_rate = float(settings['output_rate'])
            self.output_period = 1.0 / self.output_rate
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(
                repr(e)))

        GpsNmea.__init__(self,
                         self.required_fix,
                         self.required_latlon_error,
                         self.min_sats,
                         sensor_id=sensor_id,
                         instrument_id=instrument_id,
                         context=context,
                         connect_endpoint=connect_endpoint)

        self.desired_read_period = self.output_period

        # Set to true once told user that end of file has been reached.
        self.warned_about_eof = False

        self.test_file = None

        # Set to true to run image latency tests instead of reading from file.
        self.latency_test = False
        self.latency_test_period = 0.001
        self.latency_test_start_utc = 0
        self.latency_mode_run_count = 0
Beispiel #14
0
    def special_command_clicked(self):

        obj_ref = make_unicode(self.sender()).split()[3]    # TODO get rid of split, here and in setup_special_commands
        command = self.special_commands_references[obj_ref]

        # Set command arguments for special commands.
        command_args = None

        if command in ['save_primary', 'save_position']:
            user_notes, ok = QInputDialog.getText(self, 'Text Input Dialog', 'Notes:')
            if not ok:
                return # user cancelled so don't send command
            command_args = user_notes

        self.presenter.send_sensor_command(command, command_args)
Beispiel #15
0
    def invalidate_button_clicked(self):

        question = "Are you sure you want to invalidate the current session?  This will add an 'invalidated.txt' file to the output directory. No data will be lost."
        if not self.presenter.view.confirm_question(question):
            return

        notes = make_unicode(self.session_notes.toPlainText()).strip()

        self.presenter.send_controller_command('invalidate_session',
                                               send_to_all_controllers=False)
        self.presenter.send_controller_command('stop_session',
                                               notes,
                                               send_to_all_controllers=False)

        self.close()
Beispiel #16
0
    def update_sensor_view(self, info_name, value):

        # Update all screen objects that correspond to the specified sensor info name.
        matching_obj = self.info_name_to_object.get(info_name, [])
        if not isinstance(matching_obj, list):
            matching_obj.setText(make_unicode(value))
        else:
            for i, obj in enumerate(matching_obj):
                obj.setText(make_unicode(value[i]))

        if info_name == 'settings':
            settings = value
            for setting_name, setting_value in settings.iteritems():
                if setting_name in self.setting_name_to_object:
                    obj = self.setting_name_to_object[setting_name]
                    obj.setText(make_unicode(setting_value))

        if info_name == 'overall_health':
            self.overall_sensor_health_update(value)

        if info_name == 'sensor_paused':
            if value == True:
                self.paused_label.setText('Paused')
            elif value == False:
                self.paused_label.setText('Active')

        if info_name == 'sensor_state':
            self.sensor_state_value_label.setText(pretty(value))

        if info_name == 'connection_state':
            current_connection_state = value
            if current_connection_state == 'setup' and self.last_connection_state != 'setup':
                self.sensor_message_center_text_edit.clear()
                for line_edit in self.data_line_edits:
                    line_edit.clear()
            self.last_connection_state = current_connection_state
Beispiel #17
0
    def __init__(self, sensor_id, instrument_id, settings, context,
                 connect_endpoint):
        '''
        Constructor.

        Args:
            sensor_id - unique ID assigned by the program.
            settings - dictionary of sensor settings. Must include:
                output_rate - how fast to output data (Hz)
                test_float - any number that is a floating point number
                test_int - should be between 0 and 100.
                test_string - any string that's not empty
                test_bool - either true / false. Just used for testing UI.
            context - ZMQ context instance.
            connect_endpoint - endpoint on local host to receive time/commands from.

        Raises:
            ValueError - if not all settings are provided or not in correct format.
        '''
        SensorBase.__init__(self, sensor_id, instrument_id, context,
                            connect_endpoint)

        try:
            self.output_rate = float(settings['output_rate'])
            self.test_float = float(settings['test_float'])
            self.test_int = int(settings['test_int'])
            self.test_string = make_unicode(settings['test_string'])
            self.test_bool = bool(settings['test_bool'])
            self.output_period = 1.0 / self.output_rate
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(
                repr(e)))

        # Set base class fields.
        self.desired_read_period = self.output_period
        self.max_closing_time = 2

        # Counter for each time data has been generated.
        self.counter = 0

        # Flag that can be overridden with special command for testing.
        self.data_quality_ok = True

        # Flag that can be set to true for sending events for doing time testing.
        self.send_time_test_events = False

        # Flag to signify that the sensor is 'closed'
        self.closed = True
Beispiel #18
0
    def _setup_ui(self):

        self.widget_font = QFont('mapping_font', pointSize=12)

        self.clear_map_button = QtGui.QPushButton('Clear Map')
        self.clear_map_button.setFont(self.widget_font)

        # Create widgets
        self.update_rate_line_edit = QtGui.QLineEdit()
        self.update_rate_line_edit.setText(
            make_unicode(self.default_min_update_distance))
        self.update_rate_line_edit.setMaximumWidth(
            (QFontMetrics(self.widget_font).width('01.23')))
        #self.update_rate_line_edit.setInputMask('00.0')
        self.update_rate_label = QtGui.QLabel('Update Distance')
        self.update_rate_units_label = QtGui.QLabel('(meters)')
        self.spacer1 = QtGui.QSpacerItem(1, 1, QSizePolicy.Expanding,
                                         QSizePolicy.Minimum)
        self.spacer2 = QtGui.QSpacerItem(1, 1, QSizePolicy.Expanding,
                                         QSizePolicy.Minimum)

        self.fix_aspect_checkbox = QCheckBox()
        self.fix_aspect_checkbox.setText('Fix Aspect Ratio')
        self.fix_aspect_checkbox.setFont(self.widget_font)
        self.fix_aspect_checkbox.setChecked(True)
        self._fix_aspect_toggled(self.fix_aspect_checkbox.isChecked())

        self.update_rate_label.setFont(self.widget_font)
        self.update_rate_line_edit.setFont(self.widget_font)
        self.update_rate_units_label.setFont(self.widget_font)

        # Add widgets to layout
        main_layout = QtGui.QVBoxLayout(self)
        main_layout.addWidget(self.map_view)

        bottom_row_layout = QtGui.QHBoxLayout()
        bottom_row_layout.addWidget(self.update_rate_label)
        bottom_row_layout.addWidget(self.update_rate_line_edit)
        bottom_row_layout.addWidget(self.update_rate_units_label)
        bottom_row_layout.addSpacerItem(self.spacer1)
        bottom_row_layout.addWidget(self.fix_aspect_checkbox)
        bottom_row_layout.addSpacerItem(self.spacer2)
        bottom_row_layout.addWidget(self.clear_map_button)

        main_layout.addLayout(bottom_row_layout)

        self.map_view.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Expanding)
Beispiel #19
0
    def update_data_visualization(self, data):

        for n, line_edit in enumerate(self.data_line_edits):

            try:
                data_value = data[n]
            except IndexError:
                continue # not all data was provided

            if isinstance(data_value, float):

                desired_decimal_places = self.dec_places[n]

                if desired_decimal_places == 0: # (number not specified)
                    data_value = limit_decimal_places(data_value, 5)
                else:
                    data_value = format_decimal_places(data_value, desired_decimal_places)

            line_edit.setText(make_unicode(data_value))
Beispiel #20
0
    def __init__(self, sensor_id, instrument_id, settings, context, connect_endpoint):
        '''
        Constructor. Save properties for opening serial port later.
        '''
        SensorBase.__init__(self, sensor_id, instrument_id, context, connect_endpoint, throttle_sensor_read=False)

        try:
            self.port = make_unicode(settings['port'])
            self.baud = int(settings['baud'])
            self.receive_period = 1.0 / float(settings['receive_rate'])
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(e))

        # Set base class fields.  Set read period higher since sensor read throttle is disabled.
        self.desired_read_period = self.receive_period + 1
        self.max_closing_time = 3 # seconds

        # Serial port connection.
        self.connection = None

        # Used for converting raw data into glob messages.
        self.parser = GlobParser()
Beispiel #21
0
    def run(self):

        try:
            self.run_message_loop()
        except Exception as e:
            formatted_lines = traceback.format_exc().splitlines()
            traceback_lines = formatted_lines[:-1]

            error_lines = []
            error_lines.append("------------")
            error_lines.append("{} - {}".format(
                type(e).__name__, make_unicode(e)))
            for traceback_line in traceback_lines:
                error_lines.append(traceback_line)
            error_lines.append("------------")

            # Notify everyone that this manager crashed.
            # TODO this isn't really a controller event
            self.handle_controller_event(self.controllers[0],
                                         'manager_crashed', error_lines)
        finally:
            self.close_down()
Beispiel #22
0
    def __init__(self, sensor_id, instrument_id, settings, context, connect_endpoint):
        '''
        Constructor. Save properties for opening serial port later.

        Args:
            sensor_id - unique ID assigned by the program.
            settings - dictionary of sensor settings. Must include:
                port - serial port name (e.g. 'COM20')
                baud - serial port rate in bits per second.
                sample_rate - how quickly to read data in Hz
            context - ZMQ context instance.
            connect_endpoint - endpoint on local host to receive time/commands from.

        Raises:
            ValueError - if not all settings are provided or not in correct format.
        '''
        SensorBase.__init__(self, sensor_id, instrument_id, context, connect_endpoint)

        try:
            self.port = make_unicode(settings['port'])
            self.baud = int(settings['baud'])
            self.sample_period = 1.0 / float(settings['sample_rate'])
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(e))

        # Set base class fields.
        self.desired_read_period = self.sample_period
        self.max_closing_time = 3 # seconds

        # Serial port connection.
        self.connection = None

        # Time the data was requested
        self.utc_time_of_request = 0
        self.sys_time_of_request = 0

        # How many bytes to read each time sensor sends data.
        self.bytes_to_read = 2
Beispiel #23
0
    def __init__(self, sensor_id, instrument_id, settings, context,
                 connect_endpoint):
        '''
        Constructor. Save properties for opening serial port later.

        Args:
            sensor_id - unique ID assigned by the program.
            settings - dictionary of sensor settings. Must include:
                port - serial port name (e.g. 'COM20')
                baud - serial port rate in bits per second.
            context - ZMQ context instance.
            connect_endpoint - endpoint on local host to receive time/commands from.

        Raises:
            ValueError - if not all settings are provided or not in correct format.
        '''
        SensorBase.__init__(self,
                            sensor_id,
                            instrument_id,
                            context,
                            connect_endpoint,
                            throttle_sensor_read=False)

        try:
            self.port = make_unicode(settings['port'])
            self.baud = int(settings['baud'])
        except (KeyError, ValueError, ZeroDivisionError) as e:
            raise ValueError("Bad sensor setting.  Exception {}".format(e))

        # Set base class fields. Set read period to how long we want the sensor to complain after not receiving data.
        self.desired_read_period = 2
        self.max_closing_time = 3  # seconds

        # Serial port connection.
        self.connection = None

        # Buffer of bytes that haven't been converted into a distance yet.
        self.byte_buffer = []
Beispiel #24
0
    def setup_special_commands(self, special_commands):

        if special_commands == None:
            self.special_commands_group_box.deleteLater()
            return

        #special commands dict
        #key = reference
        #value = special command
        self.special_commands_references = {}

        special_commands_layout = QtGui.QHBoxLayout()
        self.special_commands_group_box.setLayout(special_commands_layout)
        for command in special_commands:

            b = QtGui.QPushButton(pretty(command))
            special_commands_layout.addWidget(b)

            # store the button object reference
            obj_ref = make_unicode(b).split()[3]
            self.special_commands_references[obj_ref] = command

            b.clicked.connect(self.special_command_clicked)
 def last_saved_config_file_path(self, new_value):
     self.qt_settings.setValue("last_saved_config_file_path",
                               make_unicode(new_value))
 def last_saved_config_file_path(self):
     file_path = self.qt_settings.value("last_saved_config_file_path")
     if file_path is None:
         file_path = os.path.join(os.path.expanduser('~'),
                                  'dysense_config.yaml')
     return make_unicode(file_path)
    def show_stacked_widget(self, widget_ref):

        widget_title = self.widget_titles[widget_ref]

        self.stacked_group_box.setTitle(make_unicode(widget_title))
        self.stacked_widget.setCurrentWidget(widget_ref)
 def last_loaded_config_file_path(self):
     file_path = self.qt_settings.value("last_loaded_config_file_path")
     return make_unicode(file_path)
Beispiel #29
0
    def cancel_button_clicked(self):

        self.controller_view.update_session_notes(
            make_unicode(self.session_notes.toPlainText()).strip())

        self.close()
Beispiel #30
0
    def append_sensor_message(self, controller_id, sensor_id, text):

        sensor_view = self.sensor_to_widget[(controller_id, sensor_id)]
        sensor_view.display_message(make_unicode(text).strip('[]'), True)