Пример #1
0
  def _refresh_fired(self):
    global labelItems
    self.dev_all_list = self.utils.baseline.dev_all_list
    self.dev_all_list.remove('Preset')
    self.neds_all = self.utils.baseline.neds_all
    self.neds_satisfied = self.utils.baseline.neds_satisfied
    self.neds_unsatisfied = self.utils.baseline.neds_unsatisfied
    self.neds = self.utils.baseline.neds
    self.devs = self.utils.baseline.devs
    self.times = self.utils.baseline.times
    self.presets = self.utils.baseline.presets
    self.time = time.time()

    if len(self.neds_all) > 0:
      self.plot_data.set_data('n_all', self.neds_all.T[0])
      self.plot_data.set_data('e_all', self.neds_all.T[1])
    if len(self.neds_satisfied) > 0:
      self.plot_data.set_data('n_satisfied', self.neds_satisfied.T[0])
      self.plot_data.set_data('e_satisfied', self.neds_satisfied.T[1])
    if len(self.neds_unsatisfied) > 0:
      self.plot_data.set_data('n_unsatisfied', self.neds_unsatisfied.T[0])
      self.plot_data.set_data('e_unsatisfied', self.neds_unsatisfied.T[1])
    labelItems, csv_text = self._max_depth_time()

    path_to_file = os.path.join(determine_path(), 'summary.csv')
    summary_file = open(path_to_file, 'w')
    summary_file.write(csv_text)
    summary_file.close()
Пример #2
0
    def _refresh_fired(self):
        global labelItems
        self.dev_all_list = self.utils.baseline.dev_all_list
        self.dev_all_list.remove('Preset')
        self.neds_all = self.utils.baseline.neds_all
        self.neds_satisfied = self.utils.baseline.neds_satisfied
        self.neds_unsatisfied = self.utils.baseline.neds_unsatisfied
        self.neds = self.utils.baseline.neds
        self.devs = self.utils.baseline.devs
        self.times = self.utils.baseline.times
        self.presets = self.utils.baseline.presets
        self.time = time.time()

        if len(self.neds_all) > 0:
            self.plot_data.set_data('n_all', self.neds_all.T[0])
            self.plot_data.set_data('e_all', self.neds_all.T[1])
        if len(self.neds_satisfied) > 0:
            self.plot_data.set_data('n_satisfied', self.neds_satisfied.T[0])
            self.plot_data.set_data('e_satisfied', self.neds_satisfied.T[1])
        if len(self.neds_unsatisfied) > 0:
            self.plot_data.set_data('n_unsatisfied',
                                    self.neds_unsatisfied.T[0])
            self.plot_data.set_data('e_unsatisfied',
                                    self.neds_unsatisfied.T[1])
        labelItems, csv_text = self._max_depth_time()

        path_to_file = os.path.join(determine_path(), 'summary.csv')
        summary_file = open(path_to_file, 'w')
        summary_file.write(csv_text)
        summary_file.close()
Пример #3
0
 def _read_preset_points(self, filename='preset.csv'):
     preset_points = {}
     px = []
     py = []
     try:
         if os.path.isfile(filename):
             path_to_file = filename
         else:
             path_to_file = os.path.join(determine_path(), filename)
         f = open(path_to_file, 'r')
         for i in f.readlines():
             xy = i.split(',')
             if len(xy) < 2:
                 continue
             try:
                 x = float(xy[0]) * 1e-3
                 y = float(xy[1]) * 1e-3
                 px.append(x)
                 py.append(y)
             except:
                 continue
     except:
         pass
     preset_points['e'] = px
     preset_points['n'] = py
     return preset_points
Пример #4
0
 def _read_preset_points(self, filename='preset.csv'):
   preset_points = {}
   px = []
   py = []
   try:
     if os.path.isfile(filename):
       path_to_file = filename
     else:
       path_to_file = os.path.join(determine_path(), filename)
     f = open(path_to_file, 'r')
     for i in f.readlines():
       xy = i.split(',')
       if len(xy) < 2:
         continue
       try:
         x = float(xy[0])*1e-3
         y = float(xy[1])*1e-3
         px.append(x)
         py.append(y)
       except:
         continue
   except:
     pass
   preset_points['e'] = px
   preset_points['n'] = py
   return preset_points
Пример #5
0
 def __init__(self,filename):
   try:
     # check if filename exists (absolute or relative path can be given)
     if os.path.isfile(filename):
       path_to_file = filename
     # if it doesn't exist, try and see if it's in the dir as the script
     else:
       path_to_file = os.path.join(determine_path(), filename)
     stram = open(path_to_file, "r")
     temp_dict = yaml.load(stram)
     self.list_of_dicts = temp_dict
     self.warned_dict = {}
     # inform user of success or failure
     print "Loaded settings yaml file from path " + path_to_file
     print "Number of settings loaded {0}".format(len(self.list_of_dicts))
   except:
     import traceback
     traceback.print_exc()
Пример #6
0
class SwiftConsole(HasTraits):
    """Traits-defined Swift Console.

    link : object
      Serial driver
    update : bool
      Update the firmware
    log_level_filter : str
      Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG".
    skip_settings : bool
      Don't read the device settings. Set to False when the console is reading
      from a network connection only.

    """

    link = Instance(sbpc.Handler)
    console_output = Instance(OutputList())
    python_console_env = Dict
    device_serial = Str('')
    dev_id = Str('')
    tracking_view = Instance(TrackingView)
    solution_view = Instance(SolutionView)
    baseline_view = Instance(BaselineView)
    observation_view = Instance(ObservationView)
    networking_view = Instance(SbpRelayView)
    observation_view_base = Instance(ObservationView)
    system_monitor_view = Instance(SystemMonitorView)
    settings_view = Instance(SettingsView)
    update_view = Instance(UpdateView)
    imu_view = Instance(IMUView)
    spectrum_analyzer_view = Instance(SpectrumAnalyzerView)
    log_level_filter = Enum(list(SYSLOG_LEVELS.itervalues()))
    """"
  mode : baseline and solution view - SPP, Fixed or Float
  num_sat : baseline and solution view - number of satellites
  port : which port is Swift Device is connected to
  directory_name : location of logged files
  json_logging : enable JSON logging
  csv_logging : enable CSV logging

  """

    mode = Str('')
    num_sats = Int(0)
    cnx_desc = Str('')
    latency = Str('')
    directory_name = Directory
    json_logging = Bool(True)
    csv_logging = Bool(False)
    cnx_icon = Str('')
    heartbeat_count = Int()
    last_timer_heartbeat = Int()
    solid_connection = Bool(False)

    csv_logging_button = SVGButton(
        toggle=True,
        label='CSV log',
        tooltip='start CSV logging',
        toggle_tooltip='stop CSV logging',
        filename=os.path.join(determine_path(), 'images', 'iconic',
                              'pause.svg'),
        toggle_filename=os.path.join(determine_path(), 'images', 'iconic',
                                     'play.svg'),
        orientation='vertical',
        width=2,
        height=2,
    )
    json_logging_button = SVGButton(
        toggle=True,
        label='JSON log',
        tooltip='start JSON logging',
        toggle_tooltip='stop JSON logging',
        filename=os.path.join(determine_path(), 'images', 'iconic',
                              'pause.svg'),
        toggle_filename=os.path.join(determine_path(), 'images', 'iconic',
                                     'play.svg'),
        orientation='vertical',
        width=2,
        height=2,
    )
    paused_button = SVGButton(label='',
                              tooltip='Pause console update',
                              toggle_tooltip='Resume console update',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=8,
                              height=8)
    clear_button = SVGButton(label='',
                             tooltip='Clear console buffer',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=8,
                             height=8)

    view = View(VSplit(
        Tabbed(Item('tracking_view', style='custom', label='Tracking'),
               Item('solution_view', style='custom', label='Solution'),
               Item('baseline_view', style='custom', label='Baseline'),
               VSplit(
                   Item('observation_view', style='custom', show_label=False),
                   Item('observation_view_base',
                        style='custom',
                        show_label=False),
                   label='Observations',
               ),
               Item('settings_view', style='custom', label='Settings'),
               Item('update_view', style='custom', label='Firmware Update'),
               Tabbed(Item('system_monitor_view',
                           style='custom',
                           label='System Monitor'),
                      Item('imu_view', style='custom', label='IMU'),
                      Item('networking_view',
                           label='Networking',
                           style='custom',
                           show_label=False),
                      Item('spectrum_analyzer_view',
                           label='Spectrum Analyzer',
                           style='custom'),
                      Item('python_console_env',
                           style='custom',
                           label='Python Console',
                           editor=ShellEditor()),
                      label='Advanced',
                      show_labels=False),
               show_labels=False),
        VGroup(
            VGroup(
                HGroup(
                    Spring(width=4, springy=False),
                    Item('paused_button',
                         show_label=False,
                         padding=0,
                         width=8,
                         height=8),
                    Item('clear_button', show_label=False, width=8, height=8),
                    Item('', label='Console Log', emphasized=True),
                    Item('csv_logging_button',
                         emphasized=True,
                         show_label=False,
                         width=12,
                         height=-30,
                         padding=0),
                    Item('json_logging_button',
                         emphasized=True,
                         show_label=False,
                         width=12,
                         height=-30,
                         padding=0),
                    Item(
                        'directory_name',
                        show_label=False,
                        springy=True,
                        tooltip=
                        'Choose location for file logs. Default is home/SwiftNav.',
                        height=-25,
                        enabled_when='not(json_logging or csv_logging)',
                        editor_args={'auto_set': True}),
                    UItem(
                        'log_level_filter',
                        style='simple',
                        padding=0,
                        height=8,
                        show_label=True,
                        tooltip=
                        'Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.'
                    ),
                ),
                Item('console_output',
                     style='custom',
                     editor=InstanceEditor(),
                     height=125,
                     show_label=False,
                     full_size=True),
            ),
            HGroup(
                Spring(width=4, springy=False),
                Item('',
                     label='Interface:',
                     emphasized=True,
                     tooltip='Interface for communicating with Swift device'),
                Item('cnx_desc', show_label=False, style='readonly'),
                Item('',
                     label='FIX TYPE:',
                     emphasized=True,
                     tooltip='Device Mode: SPS, Float RTK, Fixed RTK'),
                Item('mode', show_label=False, style='readonly'),
                Item('',
                     label='#Sats:',
                     emphasized=True,
                     tooltip='Number of satellites used in solution'),
                Item('num_sats', padding=2, show_label=False,
                     style='readonly'),
                Item('',
                     label='Base Latency:',
                     emphasized=True,
                     tooltip='Corrections latency (-1 means no corrections)'),
                Item('latency', padding=2, show_label=False, style='readonly'),
                Spring(springy=True),
                Item('cnx_icon',
                     show_label=False,
                     padding=0,
                     width=8,
                     height=8,
                     visible_when='solid_connection',
                     springy=False,
                     editor=ImageEditor(allow_clipping=False,
                                        image=ImageResource(
                                            'arrows_blue.png',
                                            search_path=[
                                                os.path.join(
                                                    determine_path(), 'images',
                                                    'iconic')
                                            ]))),
                Item('cnx_icon',
                     show_label=False,
                     padding=0,
                     width=8,
                     height=8,
                     visible_when='not solid_connection',
                     springy=False,
                     editor=ImageEditor(allow_clipping=False,
                                        image=ImageResource(
                                            'arrows_grey.png',
                                            search_path=[
                                                os.path.join(
                                                    determine_path(), 'images',
                                                    'iconic')
                                            ]))),
                Spring(width=4, height=-2, springy=False),
            ),
            Spring(height=1, springy=False),
        ),
    ),
                icon=icon,
                resizable=True,
                width=800,
                height=600,
                handler=ConsoleHandler(),
                title=CONSOLE_TITLE)

    def print_message_callback(self, sbp_msg, **metadata):
        try:
            encoded = sbp_msg.payload.encode('ascii', 'ignore')
            for eachline in reversed(encoded.split('\n')):
                self.console_output.write_level(
                    eachline, str_to_log_level(eachline.split(':')[0]))
        except UnicodeDecodeError:
            print("Critical Error encoding the serial stream as ascii.")

    def log_message_callback(self, sbp_msg, **metadata):
        try:
            encoded = sbp_msg.text.encode('ascii', 'ignore')
            for eachline in reversed(encoded.split('\n')):
                self.console_output.write_level(eachline, sbp_msg.level)
        except UnicodeDecodeError:
            print("Critical Error encoding the serial stream as ascii.")

    def ext_event_callback(self, sbp_msg, **metadata):
        e = MsgExtEvent(sbp_msg)
        print(
            'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s'
            % ("Rising" if
               (e.flags &
                (1 << 0)) else "Falling", e.pin, e.wn, e.tow, "good" if
               (e.flags & (1 << 1)) else "unknown"))

    def cmd_resp_callback(self, sbp_msg, **metadata):
        r = MsgCommandResp(sbp_msg)
        print("Received a command response message with code {0}".format(
            r.code))

    def _paused_button_fired(self):
        self.console_output.paused = not self.console_output.paused

    def _log_level_filter_changed(self):
        """
        Takes log level enum and translates into the mapped integer.
        Integer stores the current filter value inside OutputList.
        """
        self.console_output.log_level_filter = str_to_log_level(
            self.log_level_filter)

    def _clear_button_fired(self):
        self.console_output.clear()

    def _directory_name_changed(self):
        if self.baseline_view and self.solution_view:
            self.baseline_view.directory_name_b = self.directory_name
            self.solution_view.directory_name_p = self.directory_name
            self.solution_view.directory_name_v = self.directory_name
        if self.observation_view and self.observation_view_base:
            self.observation_view.dirname = self.directory_name
            self.observation_view_base.dirname = self.directory_name

    def check_heartbeat(self):
        # if our heartbeat hasn't changed since the last timer interval the connection must have dropped
        if self.heartbeat_count == self.last_timer_heartbeat:
            self.solid_connection = False
        else:
            self.solid_connection = True
        self.last_timer_heartbeat = self.heartbeat_count

    def update_on_heartbeat(self, sbp_msg, **metadata):
        self.heartbeat_count += 1
        # First initialize the state to nothing, if we can't update, it will be none
        temp_mode = "None"
        temp_num_sats = 0
        view = None
        if self.baseline_view and self.solution_view:
            # If we have a recent baseline update, we use the baseline info
            if time.time() - self.baseline_view.last_btime_update < 10:
                view = self.baseline_view
            # Otherwise, if we have a recent SPP update, we use the SPP
            elif time.time() - self.solution_view.last_stime_update < 10:
                view = self.solution_view
            if view:
                if view.last_soln:
                    # if all is well we update state
                    temp_mode = mode_dict.get(get_mode(view.last_soln),
                                              EMPTY_STR)
                    temp_num_sats = view.last_soln.n_sats

        self.mode = temp_mode
        self.num_sats = temp_num_sats

        if self.settings_view:  # for auto populating surveyed fields
            self.settings_view.lat = self.solution_view.latitude
            self.settings_view.lon = self.solution_view.longitude
            self.settings_view.alt = self.solution_view.altitude
        if self.system_monitor_view:
            if self.system_monitor_view.msg_obs_window_latency_ms != -1:
                self.latency = "{0} ms".format(
                    self.system_monitor_view.msg_obs_window_latency_ms)
            else:
                self.latency = EMPTY_STR

    def _csv_logging_button_action(self):
        if self.csv_logging and self.baseline_view.logging_b and self.solution_view.logging_p and self.solution_view.logging_v:
            print("Stopped CSV logging")
            self.csv_logging = False
            self.baseline_view.logging_b = False
            self.solution_view.logging_p = False
            self.solution_view.logging_v = False

        else:
            print("Started CSV logging at %s" % self.directory_name)
            self.csv_logging = True
            self.baseline_view.logging_b = True
            self.solution_view.logging_p = True
            self.solution_view.logging_v = True

    def _start_json_logging(self, override_filename=None):
        if override_filename:
            filename = override_filename
        else:
            filename = time.strftime("swift-gnss-%Y%m%d-%H%M%S.sbp.json")
            filename = os.path.normpath(
                os.path.join(self.directory_name, filename))
        self.logger = s.get_logger(True, filename)
        self.forwarder = sbpc.Forwarder(self.link, self.logger)
        self.forwarder.start()
        if self.settings_view:
            self.settings_view._settings_read_button_fired()

    def _stop_json_logging(self):
        fwd = self.forwarder
        fwd.stop()
        self.logger.flush()
        self.logger.close()

    def _json_logging_button_action(self):
        if self.first_json_press and self.json_logging:
            print(
                "JSON Logging initiated via CMD line.  Please press button again to stop logging"
            )
        elif self.json_logging:
            self._stop_json_logging()
            self.json_logging = False
            print("Stopped JSON logging")
        else:
            self._start_json_logging()
            self.json_logging = True
        self.first_json_press = False

    def _json_logging_button_fired(self):
        if not os.path.exists(self.directory_name) and not self.json_logging:
            confirm_prompt = CallbackPrompt(
                title="Logging directory creation",
                actions=[ok_button],
                callback=self._json_logging_button_action)
            confirm_prompt.text = "\nThe selected logging directory does not exist and will be created."
            confirm_prompt.run(block=False)
        else:
            self._json_logging_button_action()

    def _csv_logging_button_fired(self):
        if not os.path.exists(self.directory_name) and not self.csv_logging:
            confirm_prompt = CallbackPrompt(
                title="Logging directory creation",
                actions=[ok_button],
                callback=self._csv_logging_button_action)
            confirm_prompt.text = "\nThe selected logging directory does not exist and will be created."
            confirm_prompt.run(block=False)
        else:
            self._csv_logging_button_action()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.console_output.close()

    def __init__(self,
                 link,
                 update,
                 log_level_filter,
                 skip_settings=False,
                 error=False,
                 cnx_desc=None,
                 json_logging=False,
                 log_dirname=None,
                 override_filename=None,
                 log_console=False,
                 networking=None,
                 serial_upgrade=False):
        self.error = error
        self.cnx_desc = cnx_desc
        self.dev_id = cnx_desc
        self.num_sats = 0
        self.mode = ''
        self.forwarder = None
        self.latency = '--'
        # if we have passed a logfile, we set our directory to it
        override_filename = override_filename
        home = expanduser("~")
        swift_path = os.path.normpath(os.path.join(home, 'SwiftNav'))

        if log_dirname:
            self.directory_name = log_dirname
            if override_filename:
                override_filename = os.path.join(log_dirname,
                                                 override_filename)
        else:
            self.directory_name = swift_path

        # Start swallowing sys.stdout and sys.stderr
        self.console_output = OutputList(tfile=log_console,
                                         outdir=self.directory_name)
        sys.stdout = self.console_output
        self.console_output.write("Console: " + CONSOLE_VERSION +
                                  " starting...")
        if not error:
            sys.stderr = self.console_output

        self.log_level_filter = log_level_filter
        self.console_output.log_level_filter = str_to_log_level(
            log_level_filter)
        try:
            self.link = link
            self.link.add_callback(self.print_message_callback,
                                   SBP_MSG_PRINT_DEP)
            self.link.add_callback(self.log_message_callback, SBP_MSG_LOG)
            self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT)
            self.link.add_callback(self.cmd_resp_callback,
                                   SBP_MSG_COMMAND_RESP)
            self.link.add_callback(self.update_on_heartbeat, SBP_MSG_HEARTBEAT)
            self.dep_handler = DeprecatedMessageHandler(link)
            settings_read_finished_functions = []
            self.tracking_view = TrackingView(self.link)
            self.solution_view = SolutionView(self.link,
                                              dirname=self.directory_name)
            self.baseline_view = BaselineView(self.link,
                                              dirname=self.directory_name)
            self.observation_view = ObservationView(
                self.link,
                name='Local',
                relay=False,
                dirname=self.directory_name)
            self.observation_view_base = ObservationView(
                self.link,
                name='Remote',
                relay=True,
                dirname=self.directory_name)
            self.system_monitor_view = SystemMonitorView(self.link)
            self.update_view = UpdateView(self.link,
                                          download_dir=swift_path,
                                          prompt=update,
                                          serial_upgrade=serial_upgrade)
            self.imu_view = IMUView(self.link)
            self.spectrum_analyzer_view = SpectrumAnalyzerView(self.link)
            settings_read_finished_functions.append(
                self.update_view.compare_versions)
            if networking:
                import yaml
                try:
                    networking_dict = yaml.load(networking)
                    networking_dict.update({'show_networking': True})
                except yaml.YAMLError:
                    print(
                        "Unable to interpret networking cmdline argument.  It will be ignored."
                    )
                    import traceback
                    print(traceback.format_exc())
                    networking_dict = {'show_networking': True}
            else:
                networking_dict = {}
            networking_dict.update(
                {'whitelist': [SBP_MSG_POS_LLH, SBP_MSG_HEARTBEAT]})
            self.networking_view = SbpRelayView(self.link, **networking_dict)
            self.json_logging = json_logging
            self.csv_logging = False
            self.first_json_press = True
            if json_logging:
                self._start_json_logging(override_filename)
                self.json_logging = True
            # we set timer interval to 1200 milliseconds because we expect a heartbeat each second
            self.timer_cancel = call_repeatedly(1.2, self.check_heartbeat)

            # Once we have received the settings, update device_serial with
            # the Swift serial number which will be displayed in the window
            # title. This callback will also update the header route as used
            # by the networking view.

            def update_serial():
                uuid = None
                mfg_id = None
                try:
                    uuid = self.settings_view.settings['system_info'][
                        'uuid'].value
                    mfg_id = self.settings_view.settings['system_info'][
                        'serial_number'].value
                except KeyError:
                    pass
                if mfg_id:
                    self.device_serial = 'PK' + str(mfg_id)[-6:]
                self.networking_view.set_route(uuid=uuid, serial_id=mfg_id)
                if self.networking_view.connect_when_uuid_received:
                    self.networking_view._connect_rover_fired()

            settings_read_finished_functions.append(update_serial)
            self.settings_view = SettingsView(self.link,
                                              settings_read_finished_functions,
                                              skip=skip_settings)
            self.update_view.settings = self.settings_view.settings
            self.python_console_env = {
                'send_message': self.link,
                'link': self.link,
            }
            self.python_console_env.update(
                self.tracking_view.python_console_cmds)
            self.python_console_env.update(
                self.solution_view.python_console_cmds)
            self.python_console_env.update(
                self.baseline_view.python_console_cmds)
            self.python_console_env.update(
                self.observation_view.python_console_cmds)
            self.python_console_env.update(
                self.networking_view.python_console_cmds)
            self.python_console_env.update(
                self.system_monitor_view.python_console_cmds)
            self.python_console_env.update(
                self.update_view.python_console_cmds)
            self.python_console_env.update(self.imu_view.python_console_cmds)
            self.python_console_env.update(
                self.settings_view.python_console_cmds)
            self.python_console_env.update(
                self.spectrum_analyzer_view.python_console_cmds)

        except:
            import traceback
            traceback.print_exc()
            if self.error:
                sys.exit(1)
Пример #7
0
class SystemMonitorView(HasTraits):
    python_console_cmds = Dict()

    _threads_table_list = List()
    threads = List()

    _network_info = List()

    msg_obs_avg_latency_ms = Int(0)
    msg_obs_min_latency_ms = Int(0)
    msg_obs_max_latency_ms = Int(0)
    msg_obs_window_latency_ms = Int(0)

    msg_obs_avg_period_ms = Int(0)
    msg_obs_min_period_ms = Int(0)
    msg_obs_max_period_ms = Int(0)
    msg_obs_window_period_ms = Int(0)

    piksi_reset_button = SVGButton(
        label='Reset Piksi',
        tooltip='Reset Piksi',
        filename=os.path.join(determine_path(), 'images', 'fontawesome',
                              'power27.svg'),
        width=16,
        height=16,
        aligment='center')

    network_refresh_button = SVGButton(
        label='Refresh Network Status',
        tooltip='Refresh Network Status',
        filename=os.path.join(determine_path(), 'images', 'fontawesome',
                              'refresh.svg'),
        width=16,
        height=16,
        aligment='center')

    traits_view = View(
        VGroup(
            Item(
                '_threads_table_list',
                style='readonly',
                editor=TabularEditor(adapter=SimpleAdapter()),
                show_label=False,
                width=0.85, ),
            HGroup(
                VGroup(
                    HGroup(
                        VGroup(
                            Item(
                                'msg_obs_window_latency_ms',
                                label='Curr',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_avg_latency_ms',
                                label='Avg',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_min_latency_ms',
                                label='Min',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_max_latency_ms',
                                label='Max',
                                style='readonly',
                                format_str='%dms'),
                            label='Latency',
                            show_border=True),
                        VGroup(
                            Item(
                                'msg_obs_window_period_ms',
                                label='Curr',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_avg_period_ms',
                                label='Avg',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_min_period_ms',
                                label='Min',
                                style='readonly',
                                format_str='%dms'),
                            Item(
                                'msg_obs_max_period_ms',
                                label='Max',
                                style='readonly',
                                format_str='%dms'),
                            label='Period',
                            show_border=True, ),
                        show_border=True,
                        label="Observation Connection Monitor"),
                    Item('piksi_reset_button', show_label=False, width=0.50),
                ),
                VGroup(
                    Item(
                        '_network_info',
                        style='readonly',
                        editor=TabularEditor(adapter=SimpleNetworkAdapter()),
                        show_label=False, ),
                    Item(
                        'network_refresh_button', show_label=False,
                        width=0.50),
                    show_border=True,
                    label="Network"), ), ), )

    def update_threads(self):
        self._threads_table_list = [
            (thread_name, state.cpu, state.stack_free)
            for thread_name, state in sorted(
                self.threads, key=lambda x: x[1].cpu, reverse=True)
        ]

    def heartbeat_callback(self, sbp_msg, **metadata):
        if self.threads != []:
            self.update_threads()
            self.threads = []

    def thread_state_callback(self, sbp_msg, **metadata):
        if sbp_msg.name == '':
            sbp_msg.name = '(no name)'
        sbp_msg.cpu /= 10.
        self.threads.append((sbp_msg.name, sbp_msg))

    def _piksi_reset_button_fired(self):
        self.link(MsgReset(flags=0))

    def _network_refresh_button_fired(self):
        self._network_info = []
        self.link(MsgNetworkStateReq())

    def _network_callback(self, m, **metadata):
        self._network_info.append(
            (m.interface_name, ip_bytes_to_string(m.ipv4_address.ipv4_address),
             ((m.flags & (1 << 6)) != 0)))

    def uart_state_callback(self, m, **metadata):

        self.msg_obs_avg_latency_ms = m.latency.avg
        self.msg_obs_min_latency_ms = m.latency.lmin
        self.msg_obs_max_latency_ms = m.latency.lmax
        self.msg_obs_window_latency_ms = m.latency.current
        if m.msg_type == SBP_MSG_UART_STATE:
            self.msg_obs_avg_period_ms = m.obs_period.avg
            self.msg_obs_min_period_ms = m.obs_period.pmin
            self.msg_obs_max_period_ms = m.obs_period.pmax
            self.msg_obs_window_period_ms = m.obs_period.current

    def __init__(self, link):
        super(SystemMonitorView, self).__init__()
        self.link = link
        self.link.add_callback(self.heartbeat_callback, SBP_MSG_HEARTBEAT)
        self.link.add_callback(self.thread_state_callback,
                               SBP_MSG_THREAD_STATE)
        self.link.add_callback(self.uart_state_callback,
                               [SBP_MSG_UART_STATE, SBP_MSG_UART_STATE_DEPA])
        self.link.add_callback(self._network_callback,
                               SBP_MSG_NETWORK_STATE_RESP)

        self.python_console_cmds = {'mon': self}
Пример #8
0
else:
    ETSConfig.toolkit = 'qt4'

logging.basicConfig()

pygments.lexers.PythonLexer = PythonLexer
try:
    import pygments.lexers.c_cpp
except ImportError:
    pass

# These imports seem to be required to make pyinstaller work?
# (usually traitsui would load them automatically)
if ETSConfig.toolkit == 'qt4':
    pass
basedir = determine_path()
icon = ImageResource('icon',
                     search_path=['images',
                                  os.path.join(basedir, 'images')])

CONSOLE_TITLE = 'Swift Console v:' + CONSOLE_VERSION
BAUD_LIST = [57600, 115200, 230400, 921600, 1000000]


class ConsoleHandler(Handler):
    """
    Handler that updates the window title with the device serial number

    This Handler is used by Traits UI to manage making changes to the GUI in
    response to changes in the underlying class/data.
    """
Пример #9
0
class SolutionView(HasTraits):
    python_console_cmds = Dict()
    # we need to doubleup on Lists to store the psuedo absolutes separately
    # without rewriting everything
    lats = List()
    lngs = List()
    alts = List()

    lats_psuedo_abs = List()
    lngs_psuedo_abs = List()
    alts_psuedo_abs = List()

    table_spp = List()
    table_psuedo_abs = List()
    dops_table = List()
    pos_table_spp = List()
    vel_table = List()

    rtk_pos_note = Str(
        "It is necessary to enter the \"Surveyed Position\" settings for the base station in order to view the psuedo-absolute RTK Positions in this tab."
    )

    plot = Instance(Plot)
    plot_data = Instance(ArrayPlotData)
    # Store plots we care about for legend

    running = Bool(True)
    zoomall = Bool(False)
    position_centered = Bool(False)

    clear_button = SVGButton(label='',
                             tooltip='Clear',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=16,
                             height=16)
    zoomall_button = SVGButton(label='',
                               tooltip='Zoom All',
                               toggle=True,
                               filename=os.path.join(determine_path(),
                                                     'images', 'iconic',
                                                     'fullscreen.svg'),
                               width=16,
                               height=16)
    center_button = SVGButton(label='',
                              tooltip='Center on Solution',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'target.svg'),
                              width=16,
                              height=16)
    paused_button = SVGButton(label='',
                              tooltip='Pause',
                              toggle_tooltip='Run',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=16,
                              height=16)

    traits_view = View(
        HSplit(
            Tabbed(
                VGroup(Item('',
                            label='Single Point Position (SPP)',
                            emphasized=True),
                       Item('table_spp',
                            style='readonly',
                            editor=TabularEditor(adapter=SimpleAdapter()),
                            show_label=False,
                            width=0.3),
                       label='Single Point Position'),
                VGroup(Item('', label='RTK Position', emphasized=True),
                       Item('table_psuedo_abs',
                            style='readonly',
                            editor=TabularEditor(adapter=SimpleAdapter()),
                            show_label=False,
                            width=0.3,
                            height=0.9),
                       Item('rtk_pos_note',
                            show_label=False,
                            resizable=True,
                            editor=MultilineTextEditor(
                                TextEditor(multi_line=True)),
                            style='readonly',
                            width=0.3,
                            height=-40),
                       label='RTK Position')),
            VGroup(
                HGroup(
                    Item('paused_button', show_label=False),
                    Item('clear_button', show_label=False),
                    Item('zoomall_button', show_label=False),
                    Item('center_button', show_label=False),
                ),
                Item('plot',
                     show_label=False,
                     editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8))),
            )))

    def _zoomall_button_fired(self):
        self.zoomall = not self.zoomall

    def _center_button_fired(self):
        self.position_centered = not self.position_centered

    def _paused_button_fired(self):
        self.running = not self.running

    def _clear_button_fired(self):
        self.lats = []
        self.lngs = []
        self.alts = []
        self.lats_psuedo_abs = []
        self.lngs_psuedo_abs = []
        self.alts_psuedo_abs = []
        self.plot_data.set_data('lat', [])
        self.plot_data.set_data('lng', [])
        self.plot_data.set_data('alt', [])
        self.plot_data.set_data('t', [])
        self.plot_data.set_data('lat_ps', [])
        self.plot_data.set_data('lng_ps', [])
        self.plot_data.set_data('alt_ps', [])
        self.plot_data.set_data('t_ps', [])

    def _pos_llh_callback(self, sbp_msg, **metadata):
        # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
        # actually perform the update in the UI thread.
        if self.running:
            GUI.invoke_later(self.pos_llh_callback, sbp_msg)

    def update_table(self):
        self._table_list = self.table_spp.items()

    def pos_llh_callback(self, sbp_msg, **metadata):
        soln = MsgPosLLH(sbp_msg)
        masked_flag = soln.flags & 0x7
        if masked_flag == 0:
            psuedo_absolutes = False
        else:
            psuedo_absolutes = True
        pos_table = []

        if self.log_file is None:
            self.log_file = open(
                time.strftime("position_log_%Y%m%d-%H%M%S.csv"), 'w')
            self.log_file.write(
                "time,latitude(degrees),longitude(degrees),altitude(meters),n_sats,flags\n"
            )
        tow = soln.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        if self.week is not None:
            t = datetime.datetime(1980, 1, 6) + \
                datetime.timedelta(weeks=self.week) + \
                datetime.timedelta(seconds=tow)
            pos_table.append(('GPS Time', t))
            pos_table.append(('GPS Week', str(self.week)))

            self.log_file.write('%s,%.10f,%.10f,%.4f,%d,%d\n' %
                                (str(t), soln.lat, soln.lon, soln.height,
                                 soln.n_sats, soln.flags))
            self.log_file.flush()

        pos_table.append(('GPS ToW', tow))

        pos_table.append(('Num. sats', soln.n_sats))

        pos_table.append(('Lat', soln.lat))
        pos_table.append(('Lng', soln.lon))
        pos_table.append(('Alt', soln.height))
        pos_table.append(('Flags', '0x%02x' % soln.flags))
        if (soln.flags & 0xff) == 0:
            pos_table.append(('Mode', 'SPP (single point position)'))
        elif (soln.flags & 0xff) == 1:
            pos_table.append(('Mode', 'Fixed RTK'))
        elif (soln.flags & 0xff) == 2:
            pos_table.append(('Mode', 'Float RTK'))
        else:
            pos_table.append(('Mode', 'Unknown'))

        if psuedo_absolutes:
            # setup_plot variables
            self.lats_psuedo_abs.append(soln.lat)
            self.lngs_psuedo_abs.append(soln.lon)
            self.alts_psuedo_abs.append(soln.height)

            self.lats_psuedo_abs = self.lats_psuedo_abs[-1000:]
            self.lngs_psuedo_abs = self.lngs_psuedo_abs[-1000:]
            self.alts_psuedo_abs = self.alts_psuedo_abs[-1000:]

            self.plot_data.set_data('lat_ps', self.lats_psuedo_abs)
            self.plot_data.set_data('lng_ps', self.lngs_psuedo_abs)
            self.plot_data.set_data('alt_ps', self.alts_psuedo_abs)
            self.plot_data.set_data('cur_lat_ps', [soln.lat])
            self.plot_data.set_data('cur_lng_ps', [soln.lon])
            t_psuedo_abs = range(len(self.lats))
            self.plot_data.set_data('t', t)
            self.plot_data.set_data('t_ps', t_psuedo_abs)
            # set-up table variables
            self.table_psuedo_abs = pos_table

        else:
            # setup_plot variables
            self.lats.append(soln.lat)
            self.lngs.append(soln.lon)
            self.alts.append(soln.height)

            self.lats = self.lats[-1000:]
            self.lngs = self.lngs[-1000:]
            self.alts = self.alts[-1000:]

            self.plot_data.set_data('lat', self.lats)
            self.plot_data.set_data('lng', self.lngs)
            self.plot_data.set_data('alt', self.alts)
            self.plot_data.set_data('cur_lat', [soln.lat])
            self.plot_data.set_data('cur_lng', [soln.lon])
            t = range(len(self.lats))
            self.plot_data.set_data('t', t)

            # set-up table variables
            self.pos_table_spp = pos_table
            self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table
            # TODO: figure out how to center the graph now that we have two separate messages
            # when we selectivtely send only SPP, the centering function won't work anymore
            if self.position_centered:
                d = (self.plot.index_range.high -
                     self.plot.index_range.low) / 2.
                self.plot.index_range.set_bounds(soln.lon - d, soln.lon + d)
                d = (self.plot.value_range.high -
                     self.plot.value_range.low) / 2.
                self.plot.value_range.set_bounds(soln.lat - d, soln.lat + d)
        if self.zoomall:
            plot_square_axes(self.plot, 'lng', 'lat')

    def dops_callback(self, sbp_msg, **metadata):
        dops = MsgDops(sbp_msg)
        self.dops_table = [('PDOP', '%.1f' % (dops.pdop * 0.01)),
                           ('GDOP', '%.1f' % (dops.gdop * 0.01)),
                           ('TDOP', '%.1f' % (dops.tdop * 0.01)),
                           ('HDOP', '%.1f' % (dops.hdop * 0.01)),
                           ('VDOP', '%.1f' % (dops.vdop * 0.01))]
        self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table

    def vel_ned_callback(self, sbp_msg, **metadata):
        vel_ned = MsgVelNED(sbp_msg)

        if self.vel_log_file is None:
            self.vel_log_file = open(
                time.strftime("velocity_log_%Y%m%d-%H%M%S.csv"), 'w')
            self.vel_log_file.write(
                'time,north(m/s),east(m/s),down(m/s),speed(m/s),num_sats\n')

        tow = vel_ned.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        if self.week is not None:
            t = datetime.datetime(1980, 1, 6) + \
                datetime.timedelta(weeks=self.week) + \
                datetime.timedelta(seconds=tow)

            self.vel_log_file.write(
                '%s,%.6f,%.6f,%.6f,%.6f,%d\n' %
                (str(t), vel_ned.n * 1e-3, vel_ned.e * 1e-3, vel_ned.d * 1e-3,
                 math.sqrt(vel_ned.n * vel_ned.n + vel_ned.e * vel_ned.e) *
                 1e-3, vel_ned.n_sats))
            self.vel_log_file.flush()

        self.vel_table = [
            ('Vel. N', '% 8.4f' % (vel_ned.n * 1e-3)),
            ('Vel. E', '% 8.4f' % (vel_ned.e * 1e-3)),
            ('Vel. D', '% 8.4f' % (vel_ned.d * 1e-3)),
        ]
        self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table

    def gps_time_callback(self, sbp_msg, **metadata):
        self.week = MsgGPSTime(sbp_msg).wn
        self.nsec = MsgGPSTime(sbp_msg).ns

    def __init__(self, link):
        super(SolutionView, self).__init__()

        self.log_file = None
        self.vel_log_file = None

        self.plot_data = ArrayPlotData(lat=[],
                                       lng=[],
                                       alt=[],
                                       t=[],
                                       cur_lat=[],
                                       cur_lng=[],
                                       cur_lat_ps=[],
                                       cur_lng_ps=[],
                                       lat_ps=[],
                                       lng_ps=[],
                                       alt_ps=[],
                                       t_ps=[])
        self.plot = Plot(self.plot_data)

        # 1000 point buffer
        self.plot.plot(('lng', 'lat'),
                       type='line',
                       name='',
                       color=(0, 0, 0.9, 0.1))
        self.plot.plot(('lng', 'lat'),
                       type='scatter',
                       name='',
                       color='blue',
                       marker='dot',
                       line_width=0.0,
                       marker_size=1.0)
        self.plot.plot(('lng_ps', 'lat_ps'),
                       type='line',
                       name='',
                       color=(1, 0.4, 0, 0.1))
        self.plot.plot(('lng_ps', 'lat_ps'),
                       type='scatter',
                       name='',
                       color='orange',
                       marker='diamond',
                       line_width=0.0,
                       marker_size=1.0)
        # current values
        spp = self.plot.plot(('cur_lng', 'cur_lat'),
                             type='scatter',
                             name='SPP',
                             color='blue',
                             marker='plus',
                             line_width=1.5,
                             marker_size=5.0)
        rtk = self.plot.plot(('cur_lng_ps', 'cur_lat_ps'),
                             type='scatter',
                             name='RTK',
                             color='orange',
                             marker='plus',
                             line_width=1.5,
                             marker_size=5.0)
        plot_labels = ['SPP', 'RTK']
        plots_legend = dict(zip(plot_labels, [spp, rtk]))
        self.plot.legend.plots = plots_legend
        self.plot.legend.visible = True

        self.plot.index_axis.tick_label_position = 'inside'
        self.plot.index_axis.tick_label_color = 'gray'
        self.plot.index_axis.tick_color = 'gray'
        self.plot.index_axis.title = 'Longitude (degrees)'
        self.plot.index_axis.title_spacing = 5
        self.plot.value_axis.tick_label_position = 'inside'
        self.plot.value_axis.tick_label_color = 'gray'
        self.plot.value_axis.tick_color = 'gray'
        self.plot.value_axis.title = 'Latitude (degrees)'
        self.plot.value_axis.title_spacing = 5
        self.plot.padding = (25, 25, 25, 25)

        self.plot.tools.append(PanTool(self.plot))
        zt = ZoomTool(self.plot,
                      zoom_factor=1.1,
                      tool_mode="box",
                      always_on=False)
        self.plot.overlays.append(zt)

        self.link = link
        self.link.add_callback(self._pos_llh_callback, SBP_MSG_POS_LLH)
        self.link.add_callback(self.vel_ned_callback, SBP_MSG_VEL_NED)
        self.link.add_callback(self.dops_callback, SBP_MSG_DOPS)
        self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME)

        self.week = None
        self.nsec = 0

        self.python_console_cmds = {
            'solution': self,
        }
Пример #10
0
class SettingsView(HasTraits):
    """Traits-defined console settings view.

  link : object
    Serial driver object.
  read_finished_functions : list
    Callbacks to call on finishing a settings read.
  name_of_yaml_file : str
    Settings to read from (defaults to settings.yaml)
  expert : bool
    Show expert settings (defaults to False)
  gui_mode : bool
    ??? (defaults to True)
  skip : bool
    Skip reading of the settings (defaults to False). Intended for
    use when reading from network connections.
  """
    show_auto_survey = Bool(False)
    settings_yaml = list()
    auto_survey = SVGButton(
        label='Auto Survey',
        tooltip='Auto populate surveyed lat, lon and alt fields',
        filename='',
        width=16,
        height=20)
    settings_read_button = SVGButton(label='Reload',
                                     tooltip='Reload settings from Piksi',
                                     filename=os.path.join(
                                         determine_path(), 'images',
                                         'fontawesome', 'refresh.svg'),
                                     width=16,
                                     height=20)
    settings_save_button = SVGButton(label='Save to Flash',
                                     tooltip='Save settings to Flash',
                                     filename=os.path.join(
                                         determine_path(), 'images',
                                         'fontawesome', 'download.svg'),
                                     width=16,
                                     height=20)
    factory_default_button = SVGButton(
        label='Reset to Defaults',
        tooltip='Reset to Factory Defaults',
        filename=os.path.join(determine_path(), 'images', 'fontawesome',
                              'exclamation-triangle.svg'),
        width=16,
        height=20)
    settings_list = List(SettingBase)
    expert = Bool()
    selected_setting = Instance(SettingBase)
    traits_view = View(
        HSplit(
            Item(
                'settings_list',
                editor=TabularEditor(adapter=SimpleAdapter(),
                                     editable_labels=False,
                                     auto_update=True,
                                     selected='selected_setting'),
                show_label=False,
            ),
            VGroup(
                HGroup(
                    Item('settings_read_button', show_label=False),
                    Item('settings_save_button', show_label=False),
                    Item('factory_default_button', show_label=False),
                    Item('auto_survey',
                         show_label=False,
                         visible_when='show_auto_survey'),
                ),
                HGroup(
                    Item('expert',
                         label="Show Advanced Settings",
                         show_label=True)),
                Item('selected_setting', style='custom', show_label=False),
            ),
        ))

    def _selected_setting_changed(self):
        if self.selected_setting.name in [
                'surveyed_position', 'broadcast', 'surveyed_lat',
                'surveyed_lon', 'surveyed_alt'
        ]:
            self.show_auto_survey = True
        else:
            self.show_auto_survey = False

    def _expert_changed(self, info):
        try:
            self.settings_display_setup(do_read_finished=False)
        except AttributeError:
            pass

    def _settings_read_button_fired(self):
        self.enumindex = 0
        self.ordering_counter = 0
        self.link(MsgSettingsReadByIndexReq(index=self.enumindex))

    def _settings_save_button_fired(self):
        self.link(MsgSettingsSave())

    def _factory_default_button_fired(self):
        confirm_prompt = prompt.CallbackPrompt(
            title="Reset to Factory Defaults?",
            actions=[prompt.close_button, prompt.reset_button],
            callback=self.reset_factory_defaults)
        confirm_prompt.text = "This will erase all settings and then reset the device.\n" \
                            + "Are you sure you want to reset to factory defaults?"
        confirm_prompt.run(block=False)

    def reset_factory_defaults(self):
        # Reset the Piksi, with flag set to restore default settings
        self.link(MsgReset(flags=1))

    def _auto_survey_fired(self):
        confirm_prompt = prompt.CallbackPrompt(
            title="Auto populate surveyed position?",
            actions=[prompt.close_button, prompt.auto_survey_button],
            callback=self.auto_survey_fn)
        confirm_prompt.text = "\n" \
                            + "This will set the Surveyed Position section to the \n" \
                            + "mean of the SPP positions of the last 1000 SPP samples.\n \n" \
                            + "The fields that will be auto-populated are: \n" \
                            + "Surveyed Lat \n" \
                            + "Surveyed Lon \n" \
                            + "Surveyed Alt \n \n" \
                            + "The surveyed position will be an approximate value. \n" \
                            + "This may affect the relative accuracy of Piksi. \n \n" \
                            + "Are you sure you want to auto-populate the Surveyed Position section?"
        confirm_prompt.run(block=False)

    def auto_survey_fn(self):
        lat_value = str(self.lat)
        lon_value = str(self.lon)
        alt_value = str(self.alt)
        self.settings['surveyed_position']['surveyed_lat'].value = lat_value
        self.settings['surveyed_position']['surveyed_lon'].value = lon_value
        self.settings['surveyed_position']['surveyed_alt'].value = alt_value
        self.settings_display_setup(do_read_finished=False)

    ##Callbacks for receiving messages
    def settings_display_setup(self, do_read_finished=True):
        self.settings_list = []
        sections = sorted(self.settings.keys())
        for sec in sections:
            this_section = []
            for name, setting in sorted(self.settings[sec].iteritems(),
                                        key=lambda (n, s): s.ordering):
                if not setting.expert or (self.expert and setting.expert):
                    this_section.append(setting)
            if this_section:
                self.settings_list.append(SectionHeading(sec))
                self.settings_list += this_section
        # call read_finished_functions as needed
        if do_read_finished and not self.called_read_finished:
            for cb in self.read_finished_functions:
                if self.gui_mode:
                    GUI.invoke_later(cb)
                else:
                    cb()
            self.called_read_finished = True

    def settings_read_by_index_done_callback(self, sbp_msg, **metadata):
        self.settings_display_setup()

    def settings_read_by_index_callback(self, sbp_msg, **metadata):
        if not sbp_msg.payload:
            # Settings output from Piksi is terminated by an empty message.
            # Bundle up our list and display it.
            self.settings_display_setup()

        section, setting, value, format_type = sbp_msg.payload[2:].split(
            '\0')[:4]
        self.ordering_counter += 1
        if format_type == '':
            format_type = None
        else:
            setting_type, setting_format = format_type.split(':')
        if not self.settings.has_key(section):
            self.settings[section] = {}
        if format_type is None:
            # Plain old setting, no format information
            self.settings[section][setting] = Setting(
                setting,
                section,
                value,
                ordering=self.ordering_counter,
                settings=self)
        else:
            if setting_type == 'enum':
                enum_values = setting_format.split(',')
                self.settings[section][setting] = EnumSetting(
                    setting,
                    section,
                    value,
                    ordering=self.ordering_counter,
                    values=enum_values,
                    settings=self)
            else:
                # Unknown type, just treat is as a string
                self.settings[section][setting] = Setting(setting,
                                                          section,
                                                          value,
                                                          settings=self)

        self.enumindex += 1
        self.link(MsgSettingsReadByIndexReq(index=self.enumindex))

    def piksi_startup_callback(self, sbp_msg, **metadata):
        self._settings_read_button_fired()

    def set(self, section, name, value):
        self.link(
            MsgSettingsWrite(setting='%s\0%s\0%s\0' % (section, name, value)))

    def cleanup(self):
        """ Remove callbacks from serial link. """
        self.link.remove_callback(self.piksi_startup_callback, SBP_MSG_STARTUP)
        self.link.remove_callback(self.settings_read_by_index_callback,
                                  SBP_MSG_SETTINGS_READ_BY_INDEX_REQ)
        self.link.remove_callback(self.settings_read_by_index_callback,
                                  SBP_MSG_SETTINGS_READ_BY_INDEX_RESP)
        self.link.remove_callback(self.settings_read_by_index_done_callback,
                                  SBP_MSG_SETTINGS_READ_BY_INDEX_DONE)

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.cleanup()

    def __init__(self,
                 link,
                 read_finished_functions=[],
                 name_of_yaml_file="settings.yaml",
                 expert=False,
                 gui_mode=True,
                 skip=False):
        super(SettingsView, self).__init__()
        self.expert = expert
        self.show_auto_survey = False
        self.gui_mode = gui_mode
        self.enumindex = 0
        self.settings = {}
        self.link = link
        self.link.add_callback(self.piksi_startup_callback, SBP_MSG_STARTUP)
        self.link.add_callback(self.settings_read_by_index_callback,
                               SBP_MSG_SETTINGS_READ_BY_INDEX_REQ)
        self.link.add_callback(self.settings_read_by_index_callback,
                               SBP_MSG_SETTINGS_READ_BY_INDEX_RESP)
        self.link.add_callback(self.settings_read_by_index_done_callback,
                               SBP_MSG_SETTINGS_READ_BY_INDEX_DONE)
        # Read in yaml file for setting metadata
        self.settings_yaml = SettingsList(name_of_yaml_file)
        # List of functions to be executed after all settings are read.
        # No support for arguments currently.
        self.read_finished_functions = read_finished_functions
        self.called_read_finished = False
        self.setting_detail = SettingBase()
        if not skip:
            try:
                self._settings_read_button_fired()
            except IOError:
                print "IOError in settings_view startup call of _settings_read_button_fired."
                print "Verify that write permissions exist on the port."
        self.python_console_cmds = {'settings': self}
Пример #11
0
class SolutionView(HasTraits):
  python_console_cmds = Dict()
  # we need to doubleup on Lists to store the psuedo absolutes separately
  # without rewriting everything

  """
  logging_v : toggle logging for velocity files
  directory_name_v : location and name of velocity files
  logging_p : toggle logging for position files
  directory_name_p : location and name of velocity files
  """
  plot_history_max = Int(1000)
  logging_v = Bool(False)
  directory_name_v = File

  logging_p = Bool(False)
  directory_name_p = File

  lats_psuedo_abs = List()
  lngs_psuedo_abs = List()
  alts_psuedo_abs = List()

  table = List()
  dops_table = List()
  pos_table = List()
  vel_table = List()

  rtk_pos_note = Str("It is necessary to enter the \"Surveyed Position\" settings for the base station in order to view the RTK Positions in this tab.")

  plot = Instance(Plot)
  plot_data = Instance(ArrayPlotData)
  # Store plots we care about for legend

  running = Bool(True)
  zoomall = Bool(False)
  position_centered = Bool(False)

  clear_button = SVGButton(
    label='', tooltip='Clear',
    filename=os.path.join(determine_path(), 'images', 'iconic', 'x.svg'),
    width=16, height=16
  )
  zoomall_button = SVGButton(
    label='', tooltip='Zoom All', toggle=True,
    filename=os.path.join(determine_path(), 'images', 'iconic', 'fullscreen.svg'),
    width=16, height=16
  )
  center_button = SVGButton(
    label='', tooltip='Center on Solution', toggle=True,
    filename=os.path.join(determine_path(), 'images', 'iconic', 'target.svg'),
    width=16, height=16
  )
  paused_button = SVGButton(
    label='', tooltip='Pause', toggle_tooltip='Run', toggle=True,
    filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'),
    toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'),
    width=16, height=16
  )

  traits_view = View(
    HSplit(
        VGroup(
          Item('table', style='readonly',
                editor=TabularEditor(adapter=SimpleAdapter()),
                show_label=False, width=0.3),
          Item('rtk_pos_note', show_label=False, resizable=True,
            editor=MultilineTextEditor(TextEditor(multi_line=True)), 
            style='readonly', width=0.3, height=-40),
          ),
      VGroup(
        HGroup(
          Item('paused_button', show_label=False),
          Item('clear_button', show_label=False),
          Item('zoomall_button', show_label=False),
          Item('center_button', show_label=False),
        ),
        Item('plot',
          show_label=False,
          editor=ComponentEditor(bgcolor=(0.8,0.8,0.8))),
      )
    )
  )

  def _zoomall_button_fired(self):
    self.zoomall = not self.zoomall

  def _center_button_fired(self):
    self.position_centered = not self.position_centered

  def _paused_button_fired(self):
    self.running = not self.running

  def _reset_remove_current(self):
    self.plot_data.set_data('cur_lat_spp', [])
    self.plot_data.set_data('cur_lng_spp', [])
    self.plot_data.set_data('cur_alt_spp', [])
    self.plot_data.set_data('cur_lat_dgnss', [])
    self.plot_data.set_data('cur_lng_dgnss', [])
    self.plot_data.set_data('cur_alt_dgnss', [])
    self.plot_data.set_data('cur_lat_float', [])
    self.plot_data.set_data('cur_lng_float', [])
    self.plot_data.set_data('cur_alt_float', [])
    self.plot_data.set_data('cur_lat_fixed', [])
    self.plot_data.set_data('cur_lng_fixed', [])
    self.plot_data.set_data('cur_alt_fixed', [])

  def _clear_button_fired(self):
    self.tows = np.empty(self.plot_history_max)
    self.lats = np.empty(self.plot_history_max)
    self.lngs = np.empty(self.plot_history_max)
    self.alts = np.empty(self.plot_history_max)
    self.modes = np.empty(self.plot_history_max)
    self.plot_data.set_data('lat_spp', [])
    self.plot_data.set_data('lng_spp', [])
    self.plot_data.set_data('alt_spp', [])
    self.plot_data.set_data('lat_dgnss', [])
    self.plot_data.set_data('lng_dgnss', [])
    self.plot_data.set_data('alt_dgnss', [])
    self.plot_data.set_data('lat_float', [])
    self.plot_data.set_data('lng_float', [])
    self.plot_data.set_data('alt_float', [])
    self.plot_data.set_data('lat_fixed', [])
    self.plot_data.set_data('lng_fixed', [])
    self.plot_data.set_data('alt_fixed', [])
    self._reset_remove_current()


  def _pos_llh_callback(self, sbp_msg, **metadata):
    # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
    # actually perform the update in the UI thread.
    if self.running:
      GUI.invoke_later(self.pos_llh_callback, sbp_msg)

  def update_table(self):
    self._table_list = self.table_spp.items()

  def auto_survey(self):
    if self.counter < 1000:
      self.counter = self.counter + 1
    self.latitude_list.append(self.last_soln.lat)
    self.longitude_list.append(self.last_soln.lon)
    self.altitude_list.append(self.last_soln.height)
    self.latitude_list = self.latitude_list[-1000:]
    self.longitude_list = self.longitude_list[-1000:]
    self.altitude_list = self.altitude_list[-1000:]
    self.latitude = (sum(self.latitude_list))/self.counter
    self.altitude = (sum(self.altitude_list))/self.counter
    self.longitude = (sum(self.longitude_list))/self.counter

  def pos_llh_callback(self, sbp_msg, **metadata):
    if sbp_msg.msg_type == SBP_MSG_POS_LLH_DEP_A:
      soln = MsgPosLLHDepA(sbp_msg)
    else:
      soln = MsgPosLLH(sbp_msg)
    self.last_soln = soln

    self.last_pos_mode = get_mode(soln)
    pos_table = []
    soln.h_accuracy *= 1e-3
    soln.v_accuracy *= 1e-3

    tow = soln.tow * 1e-3
    if self.nsec is not None:
      tow += self.nsec * 1e-9

    if self.week is not None:
      t = datetime.datetime(1980, 1, 6) + \
          datetime.timedelta(weeks=self.week) + \
          datetime.timedelta(seconds=tow)
      tstr = t.strftime('%Y-%m-%d %H:%M')
      secs = t.strftime('%S.%f')
     
      if(self.directory_name_p == ''):
        filepath_p = time.strftime("position_log_%Y%m%d-%H%M%S.csv")
      else:
        filepath_p = os.path.join(self.directory_name_p, time.strftime("position_log_%Y%m%d-%H%M%S.csv"))

      if self.logging_p ==  False:
        self.log_file = None

      if self.logging_p:
        if self.log_file is None:
          self.log_file = open(filepath_p, 'w')
          self.log_file.write("time,latitude(degrees),longitude(degrees),altitude(meters),"
                              "h_accuracy(meters),v_accuracy(meters),n_sats,flags\n")

        self.log_file.write('%s,%.10f,%.10f,%.4f,%.4f,%.4f,%d,%d\n' % (
          str(t),
          soln.lat, soln.lon, soln.height,
          soln.h_accuracy, soln.v_accuracy,
          soln.n_sats, soln.flags)
        )
        self.log_file.flush()

    
    if self.last_pos_mode == 0:
      pos_table.append(('GPS Time', EMPTY_STR))
      pos_table.append(('GPS Week', EMPTY_STR))
      pos_table.append(('GPS TOW', EMPTY_STR))
      pos_table.append(('Num. Signals', EMPTY_STR))
      pos_table.append(('Lat', EMPTY_STR))
      pos_table.append(('Lng', EMPTY_STR))
      pos_table.append(('Height', EMPTY_STR))
      pos_table.append(('h_accuracy', EMPTY_STR))
      pos_table.append(('v_accuracy', EMPTY_STR))
    else:
      self.last_stime_update = time.time()
      if self.week is not None:
        pos_table.append(('GPS Time', "{0}:{1:06.3f}".format(tstr, float(secs))))
        pos_table.append(('GPS Week', str(self.week)))
      pos_table.append(('GPS TOW', "{:.3f}".format(tow)))
      pos_table.append(('Num. Sats', soln.n_sats))
      pos_table.append(('Lat', soln.lat))
      pos_table.append(('Lng', soln.lon))
      pos_table.append(('Height', soln.height))
      pos_table.append(('h_accuracy', soln.h_accuracy))
      pos_table.append(('v_accuracy', soln.v_accuracy))

    pos_table.append(('Pos Flags', '0x%03x' % soln.flags))
    pos_table.append(('Pos Fix Mode', mode_dict[self.last_pos_mode]))

    self.auto_survey()

    # setup_plot variables
    self.lats[1:] = self.lats[:-1]
    self.lngs[1:] = self.lngs[:-1]
    self.alts[1:] = self.alts[:-1]
    self.tows[1:] = self.tows[:-1]
    self.modes[1:] = self.modes[:-1]

    self.lats[0] = soln.lat
    self.lngs[0] = soln.lon
    self.alts[0] = soln.height
    self.tows[0] = soln.tow
    self.modes[0] = self.last_pos_mode

    self.lats = self.lats[-self.plot_history_max:]
    self.lngs = self.lngs[-self.plot_history_max:]
    self.alts = self.alts[-self.plot_history_max:]
    self.tows = self.tows[-self.plot_history_max:]
    self.modes = self.modes[-self.plot_history_max:]

    # SPP
    spp_indexer, dgnss_indexer, float_indexer, fixed_indexer = None, None, None, None
    if np.any(self.modes):
      spp_indexer = (self.modes == SPP_MODE)
      dgnss_indexer = (self.modes == DGNSS_MODE)
      float_indexer = (self.modes == FLOAT_MODE)
      fixed_indexer = (self.modes == FIXED_MODE)
    
    # make sure that there is at least one true in indexer before setting
      if any(spp_indexer):
        self.plot_data.set_data('lat_spp', self.lats[spp_indexer])
        self.plot_data.set_data('lng_spp', self.lngs[spp_indexer])
        self.plot_data.set_data('alt_spp', self.alts[spp_indexer])
      if any(dgnss_indexer):
        self.plot_data.set_data('lat_dgnss', self.lats[dgnss_indexer])
        self.plot_data.set_data('lng_dgnss', self.lngs[dgnss_indexer])
        self.plot_data.set_data('alt_dgnss', self.alts[dgnss_indexer])
      if any(float_indexer):
        self.plot_data.set_data('lat_float', self.lats[float_indexer])
        self.plot_data.set_data('lng_float', self.lngs[float_indexer])
        self.plot_data.set_data('alt_float', self.alts[float_indexer])
      if any(fixed_indexer):
        self.plot_data.set_data('lat_fixed', self.lats[fixed_indexer])
        self.plot_data.set_data('lng_fixed', self.lngs[fixed_indexer])
        self.plot_data.set_data('alt_fixed', self.alts[fixed_indexer])

    self._reset_remove_current()
    if self.last_pos_mode == SPP_MODE:
      self.plot_data.set_data('cur_lat_spp', [soln.lat])
      self.plot_data.set_data('cur_lng_spp', [soln.lon])
    if self.last_pos_mode == DGNSS_MODE:
      self.plot_data.set_data('cur_lat_dgnss', [soln.lat])
      self.plot_data.set_data('cur_lng_dgnss', [soln.lon])
    if self.last_pos_mode == FLOAT_MODE:
      self.plot_data.set_data('cur_lat_float', [soln.lat])
      self.plot_data.set_data('cur_lng_float', [soln.lon])
    if self.last_pos_mode == FIXED_MODE:
      self.plot_data.set_data('cur_lat_fixed', [soln.lat])
      self.plot_data.set_data('cur_lng_fixed', [soln.lon])

    # set-up table variables
    self.pos_table = pos_table
    self.table = self.pos_table + self.vel_table + self.dops_table

    # TODO: figure out how to center the graph now that we have two separate messages
    # when we selectively send only SPP, the centering function won't work anymore

    if not self.zoomall and self.position_centered:
      d = (self.plot.index_range.high - self.plot.index_range.low) / 2.
      self.plot.index_range.set_bounds(soln.lon - d, soln.lon + d)
      d = (self.plot.value_range.high - self.plot.value_range.low) / 2.
      self.plot.value_range.set_bounds(soln.lat - d, soln.lat + d)
    if self.zoomall:
      plot_square_axes(self.plot, ('lng_spp', 'lng_dgnss', 'lng_float','lng_fixed'), 
                        ('lat_spp', 'lat_dgnss', 'lat_float','lat_fixed'))

  def dops_callback(self, sbp_msg, **metadata):
    flags = 0
    if sbp_msg.msg_type == SBP_MSG_DOPS_DEP_A:
      dops = MsgDopsDepA(sbp_msg)
      flags = 1
    else:
      dops = MsgDops(sbp_msg)
      flags = dops.flags
    if flags != 0:
      self.dops_table = [
        ('PDOP', '%.1f' % (dops.pdop * 0.01)),
        ('GDOP', '%.1f' % (dops.gdop * 0.01)),
        ('TDOP', '%.1f' % (dops.tdop * 0.01)),
        ('HDOP', '%.1f' % (dops.hdop * 0.01)),
        ('VDOP', '%.1f' % (dops.vdop * 0.01))
      ]
    else:
      self.dops_table = [
        ('PDOP', EMPTY_STR),
        ('GDOP', EMPTY_STR),
        ('TDOP', EMPTY_STR),
        ('HDOP', EMPTY_STR),
        ('VDOP', EMPTY_STR)
      ]
    
    self.dops_table.append(('DOPS Flags', '0x%03x' % flags))
    self.table = self.pos_table + self.vel_table + self.dops_table

  def vel_ned_callback(self, sbp_msg, **metadata):
    flags = 0
    if sbp_msg.msg_type == SBP_MSG_VEL_NED_DEP_A:
      vel_ned = MsgVelNEDDepA(sbp_msg)
      flags = 1
    else:
      vel_ned = MsgVelNED(sbp_msg)
      flags = vel_ned.flags
    tow = vel_ned.tow * 1e-3
    if self.nsec is not None:
      tow += self.nsec * 1e-9

    if self.week is not None:
      t = datetime.datetime(1980, 1, 6) + \
          datetime.timedelta(weeks=self.week) + \
          datetime.timedelta(seconds=tow)
     
      if self.directory_name_v == '':
          filepath_v = time.strftime("velocity_log_%Y%m%d-%H%M%S.csv")
      else:
          filepath_v = os.path.join(self.directory_name_v,time.strftime("velocity_log_%Y%m%d-%H%M%S.csv"))

      if self.logging_v ==  False:
        self.vel_log_file = None

      if self.logging_v:

        if self.vel_log_file is None:
          self.vel_log_file = open(filepath_v, 'w')
          self.vel_log_file.write('time,north(m/s),east(m/s),down(m/s),speed(m/s),flags,num_signals\n')

        self.vel_log_file.write('%s,%.6f,%.6f,%.6f,%.6f,%d,%d\n' % (
          str(t),
          vel_ned.n * 1e-3, vel_ned.e * 1e-3, vel_ned.d * 1e-3,
          math.sqrt(vel_ned.n*vel_ned.n + vel_ned.e*vel_ned.e) * 1e-3,
          flags,
          vel_ned.n_sats)
        )
        self.vel_log_file.flush()
    if flags != 0: 
      self.vel_table = [
        ('Vel. N', '% 8.4f' % (vel_ned.n * 1e-3)),
        ('Vel. E', '% 8.4f' % (vel_ned.e * 1e-3)),
        ('Vel. D', '% 8.4f' % (vel_ned.d * 1e-3)),
      ]
    else:
      self.vel_table = [
        ('Vel. N', EMPTY_STR),
        ('Vel. E', EMPTY_STR),
        ('Vel. D', EMPTY_STR),
      ]
    self.vel_table.append(('Vel Flags', '0x%03x' % flags))
    self.table = self.pos_table + self.vel_table + self.dops_table

  def gps_time_callback(self, sbp_msg, **metadata):
    if sbp_msg.msg_type == SBP_MSG_GPS_TIME_DEP_A:
      time_msg = MsgGPSTimeDepA(sbp_msg)
      flags = 1
    elif sbp_msg.msg_type == SBP_MSG_GPS_TIME:
      time_msg = MsgGPSTime(sbp_msg)
      flags = time_msg.flags
      if flags != 0:
        self.week = time_msg.wn
        self.nsec = time_msg.ns

  def __init__(self, link, dirname=''):
    super(SolutionView, self).__init__()

    self.lats = np.zeros(self.plot_history_max)
    self.lngs = np.zeros(self.plot_history_max)
    self.alts = np.zeros(self.plot_history_max)
    self.tows = np.zeros(self.plot_history_max)
    self.modes = np.zeros(self.plot_history_max)
    self.log_file = None
    self.directory_name_v = dirname
    self.directory_name_p = dirname
    self.vel_log_file = None
    self.last_stime_update = 0
    self.last_soln = None

    self.counter = 0
    self.latitude_list = []
    self.longitude_list = []
    self.altitude_list = []
    self.altitude = 0
    self.longitude = 0
    self.latitude = 0
    self.last_pos_mode = 0

    self.plot_data = ArrayPlotData(lat_spp=[], lng_spp=[], alt_spp=[],
      cur_lat_spp=[], cur_lng_spp=[], lat_dgnss=[], lng_dgnss=[], alt_dgnss=[],
      cur_lat_dgnss=[], cur_lng_dgnss=[], lat_float=[], lng_float=[], alt_float=[],
      cur_lat_float=[], cur_lng_float=[], lat_fixed=[], lng_fixed=[], alt_fixed=[],
      cur_lat_fixed=[], cur_lng_fixed=[])
    self.plot = Plot(self.plot_data)

    # 1000 point buffer
    self.plot.plot(('lng_spp', 'lat_spp'), type='line', line_width=0.1, name='', color=color_dict[SPP_MODE])
    self.plot.plot(('lng_spp', 'lat_spp'), type='scatter',  name='', color=color_dict[SPP_MODE],
      marker='dot', line_width=0.0, marker_size=1.0)
    self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='line',  line_width=0.1, name='', color=color_dict[DGNSS_MODE])
    self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='scatter', name='', color=color_dict[DGNSS_MODE],
      marker='dot', line_width=0.0, marker_size=1.0)
    self.plot.plot(('lng_float', 'lat_float'), type='line',  line_width=0.1, name='', color=color_dict[FLOAT_MODE])
    self.plot.plot(('lng_float', 'lat_float'), type='scatter', name='', color=color_dict[FLOAT_MODE],
      marker='dot', line_width=0.0, marker_size=1.0)
    self.plot.plot(('lng_fixed', 'lat_fixed'), type='line',  line_width=0.1, name='', color=color_dict[FIXED_MODE])
    self.plot.plot(('lng_fixed', 'lat_fixed'), type='scatter', name='', color=color_dict[FIXED_MODE],
      marker='dot', line_width=0.0, marker_size=1.0)
    # current values
    spp = self.plot.plot(('cur_lng_spp', 'cur_lat_spp'), type='scatter', name=mode_dict[SPP_MODE],
      color=color_dict[SPP_MODE], marker='plus', line_width=1.5, marker_size=5.0)
    dgnss = self.plot.plot(('cur_lng_dgnss', 'cur_lat_dgnss'), type='scatter', name=mode_dict[DGNSS_MODE],
      color=color_dict[DGNSS_MODE], marker='plus', line_width=1.5, marker_size=5.0)
    rtkfloat = self.plot.plot(('cur_lng_float', 'cur_lat_float'), type='scatter', name=mode_dict[FLOAT_MODE],
      color=color_dict[FLOAT_MODE], marker='plus', line_width=1.5, marker_size=5.0)
    rtkfix = self.plot.plot(('cur_lng_fixed', 'cur_lat_fixed'), type='scatter', name=mode_dict[FIXED_MODE],
      color=color_dict[FIXED_MODE], marker='plus', line_width=1.5, marker_size=5.0)
    plot_labels = ['SPP', 'DGPS', "RTK float", "RTK fixed"]
    plots_legend = dict(zip(plot_labels, [spp, dgnss, rtkfloat, rtkfix]))
    self.plot.legend.plots = plots_legend
    self.plot.legend.labels = plot_labels # sets order
    self.plot.legend.visible = True

    self.plot.index_axis.tick_label_position = 'inside'
    self.plot.index_axis.tick_label_color = 'gray'
    self.plot.index_axis.tick_color = 'gray'
    self.plot.index_axis.title='Longitude (degrees)'
    self.plot.index_axis.title_spacing = 5
    self.plot.value_axis.tick_label_position = 'inside'
    self.plot.value_axis.tick_label_color = 'gray'
    self.plot.value_axis.tick_color = 'gray'
    self.plot.value_axis.title='Latitude (degrees)'
    self.plot.value_axis.title_spacing = 5
    self.plot.padding = (25, 25, 25, 25)

    self.plot.tools.append(PanTool(self.plot))
    zt = ZoomTool(self.plot, zoom_factor=1.1, tool_mode="box", always_on=False)
    self.plot.overlays.append(zt)

    self.link = link
    self.link.add_callback(self._pos_llh_callback, [SBP_MSG_POS_LLH_DEP_A, SBP_MSG_POS_LLH])
    self.link.add_callback(self.vel_ned_callback, [SBP_MSG_VEL_NED_DEP_A, SBP_MSG_VEL_NED])
    self.link.add_callback(self.dops_callback, [SBP_MSG_DOPS_DEP_A, SBP_MSG_DOPS])
    self.link.add_callback(self.gps_time_callback, [SBP_MSG_GPS_TIME_DEP_A, SBP_MSG_GPS_TIME])

    self.week = None
    self.nsec = 0

    self.python_console_cmds = {
      'solution': self,
    }
Пример #12
0
class SystemMonitorView(HasTraits):
    python_console_cmds = Dict()

    _threads_table_list = List()
    threads = List()
    uart_a_crc_error_count = Int(0)
    uart_a_io_error_count = Int(0)
    uart_a_rx_buffer = Float(0)
    uart_a_tx_buffer = Float(0)
    uart_a_tx_KBps = Float(0)
    uart_a_rx_KBps = Float(0)

    uart_b_crc_error_count = Int(0)
    uart_b_io_error_count = Int(0)
    uart_b_rx_buffer = Float(0)
    uart_b_tx_buffer = Float(0)
    uart_b_tx_KBps = Float(0)
    uart_b_rx_KBps = Float(0)

    ftdi_crc_error_count = Int(0)
    ftdi_io_error_count = Int(0)
    ftdi_rx_buffer = Float(0)
    ftdi_tx_buffer = Float(0)
    ftdi_tx_KBps = Float(0)
    ftdi_rx_KBps = Float(0)

    msg_obs_avg_latency_ms = Int(0)
    msg_obs_min_latency_ms = Int(0)
    msg_obs_max_latency_ms = Int(0)
    msg_obs_window_latency_ms = Int(0)

    msg_obs_avg_period_ms = Int(0)
    msg_obs_min_period_ms = Int(0)
    msg_obs_max_period_ms = Int(0)
    msg_obs_window_period_ms = Int(0)

    piksi_reset_button = SVGButton(label='Reset Piksi',
                                   tooltip='Reset Piksi',
                                   filename=os.path.join(
                                       determine_path(), 'images',
                                       'fontawesome', 'power27.svg'),
                                   width=16,
                                   height=16,
                                   aligment='center')

    traits_view = View(
        VGroup(
            Item(
                '_threads_table_list',
                style='readonly',
                editor=TabularEditor(adapter=SimpleAdapter()),
                show_label=False,
                width=0.85,
            ),
            HGroup(
                VGroup(
                    HGroup(VGroup(Item('msg_obs_window_latency_ms',
                                       label='Curr',
                                       style='readonly',
                                       format_str='%dms'),
                                  Item('msg_obs_avg_latency_ms',
                                       label='Avg',
                                       style='readonly',
                                       format_str='%dms'),
                                  Item('msg_obs_min_latency_ms',
                                       label='Min',
                                       style='readonly',
                                       format_str='%dms'),
                                  Item('msg_obs_max_latency_ms',
                                       label='Max',
                                       style='readonly',
                                       format_str='%dms'),
                                  label='Latency',
                                  show_border=True),
                           VGroup(
                               Item('msg_obs_window_period_ms',
                                    label='Curr',
                                    style='readonly',
                                    format_str='%dms'),
                               Item('msg_obs_avg_period_ms',
                                    label='Avg',
                                    style='readonly',
                                    format_str='%dms'),
                               Item('msg_obs_min_period_ms',
                                    label='Min',
                                    style='readonly',
                                    format_str='%dms'),
                               Item('msg_obs_max_period_ms',
                                    label='Max',
                                    style='readonly',
                                    format_str='%dms'),
                               label='Period',
                               show_border=True,
                           ),
                           show_border=True,
                           label="Observation Connection Monitor"),
                    HGroup(
                        Spring(width=50, springy=False),
                        Item('piksi_reset_button',
                             show_label=False,
                             width=0.50),
                    ),
                ),
                VGroup(
                    Item('uart_a_crc_error_count',
                         label='CRC Errors',
                         style='readonly'),
                    Item('uart_a_io_error_count',
                         label='IO Errors',
                         style='readonly'),
                    Item('uart_a_tx_buffer',
                         label='TX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('uart_a_rx_buffer',
                         label='RX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('uart_a_tx_KBps',
                         label='TX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    Item('uart_a_rx_KBps',
                         label='RX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    label='UART A',
                    show_border=True,
                ),
                VGroup(
                    Item('uart_b_crc_error_count',
                         label='CRC Errors',
                         style='readonly'),
                    Item('uart_b_io_error_count',
                         label='IO Errors',
                         style='readonly'),
                    Item('uart_b_tx_buffer',
                         label='TX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('uart_b_rx_buffer',
                         label='RX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('uart_b_tx_KBps',
                         label='TX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    Item('uart_b_rx_KBps',
                         label='RX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    label='UART B',
                    show_border=True,
                ),
                VGroup(
                    Item('ftdi_crc_error_count',
                         label='CRC Errors',
                         style='readonly'),
                    Item('ftdi_io_error_count',
                         label='IO Errors',
                         style='readonly'),
                    Item('ftdi_tx_buffer',
                         label='TX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('ftdi_rx_buffer',
                         label='RX Buffer %',
                         style='readonly',
                         format_str='%.1f'),
                    Item('ftdi_tx_KBps',
                         label='TX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    Item('ftdi_rx_KBps',
                         label='RX KBytes/s',
                         style='readonly',
                         format_str='%.2f'),
                    label='USB UART',
                    show_border=True,
                ),
            ),
        ), )

    def update_threads(self):
        self._threads_table_list = [
            (thread_name, state.cpu, state.stack_free)
            for thread_name, state in sorted(
                self.threads, key=lambda x: x[1].cpu, reverse=True)
        ]

    def heartbeat_callback(self, sbp_msg, **metadata):
        if self.threads != []:
            self.update_threads()
            self.threads = []

    def thread_state_callback(self, sbp_msg, **metadata):
        if sbp_msg.name == '':
            sbp_msg.name = '(no name)'
        sbp_msg.cpu /= 10.
        self.threads.append((sbp_msg.name, sbp_msg))

    def _piksi_reset_button_fired(self):
        self.link(MsgReset())

    def uart_state_callback(self, m, **metadata):
        self.uart_a_tx_KBps = m.uart_a.tx_throughput
        self.uart_a_rx_KBps = m.uart_a.rx_throughput
        self.uart_a_crc_error_count = m.uart_a.crc_error_count
        self.uart_a_io_error_count = m.uart_a.io_error_count
        self.uart_a_tx_buffer = 100 * m.uart_a.tx_buffer_level / 255.0
        self.uart_a_rx_buffer = 100 * m.uart_a.rx_buffer_level / 255.0

        self.uart_b_tx_KBps = m.uart_b.tx_throughput
        self.uart_b_rx_KBps = m.uart_b.rx_throughput
        self.uart_b_crc_error_count = m.uart_b.crc_error_count
        self.uart_b_io_error_count = m.uart_b.io_error_count
        self.uart_b_tx_buffer = 100 * m.uart_b.tx_buffer_level / 255.0
        self.uart_b_rx_buffer = 100 * m.uart_b.rx_buffer_level / 255.0

        self.uart_ftdi_tx_KBps = m.uart_ftdi.tx_throughput
        self.uart_ftdi_rx_KBps = m.uart_ftdi.rx_throughput
        self.uart_ftdi_crc_error_count = m.uart_ftdi.crc_error_count
        self.uart_ftdi_io_error_count = m.uart_ftdi.io_error_count
        self.uart_ftdi_tx_buffer = 100 * m.uart_ftdi.tx_buffer_level / 255.0
        self.uart_ftdi_rx_buffer = 100 * m.uart_ftdi.rx_buffer_level / 255.0

        self.msg_obs_avg_latency_ms = m.latency.avg
        self.msg_obs_min_latency_ms = m.latency.lmin
        self.msg_obs_max_latency_ms = m.latency.lmax
        self.msg_obs_window_latency_ms = m.latency.current
        if m.msg_type == SBP_MSG_UART_STATE:
            self.msg_obs_avg_period_ms = m.obs_period.avg
            self.msg_obs_min_period_ms = m.obs_period.pmin
            self.msg_obs_max_period_ms = m.obs_period.pmax
            self.msg_obs_window_period_ms = m.obs_period.current

    def __init__(self, link):
        super(SystemMonitorView, self).__init__()
        self.link = link
        self.link.add_callback(self.heartbeat_callback, SBP_MSG_HEARTBEAT)
        self.link.add_callback(self.thread_state_callback,
                               SBP_MSG_THREAD_STATE)
        self.link.add_callback(self.uart_state_callback,
                               [SBP_MSG_UART_STATE, SBP_MSG_UART_STATE_DEPA])

        self.python_console_cmds = {'mon': self}
Пример #13
0
class BaselineView(HasTraits):
    python_console_cmds = Dict()

    plot = Instance(Plot)
    plot_data = Instance(ArrayPlotData)

    running = Bool(True)
    zoomall = Bool(False)

    clear_button = SVGButton(label='',
                             tooltip='Clear',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=16,
                             height=16)
    zoomall_button = SVGButton(label='',
                               tooltip='Zoom All',
                               toggle=True,
                               filename=os.path.join(determine_path(),
                                                     'images', 'iconic',
                                                     'fullscreen.svg'),
                               width=16,
                               height=16)
    paused_button = SVGButton(label='',
                              tooltip='Pause',
                              toggle_tooltip='Run',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=16,
                              height=16)

    position_threshold = Str()
    depth_threshold = Str()
    time_threshold = Str()

    focused_dev = Str
    dev_all_list = List(['All', 'Preset'])

    traits_view = View(
        HSplit(
            VGroup(
                HGroup(
                    Item('paused_button', show_label=False),
                    Item('clear_button', show_label=False),
                    Item('zoomall_button', show_label=False),
                    Item('focused_dev',
                         editor=EnumEditor(name='dev_all_list'),
                         label=u'焦点'), Spring(),
                    HGroup(
                        Item('position_threshold',
                             editor=TextEditor(auto_set=False, enter_set=True),
                             label=u'位置阈值'),
                        Item('depth_threshold',
                             editor=TextEditor(),
                             label=u'深度阈值'),
                        Item('time_threshold',
                             editor=TextEditor(),
                             label=u'时间阈值'),
                    )),
                Item(
                    'plot',
                    show_label=False,
                    editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)),
                ))), )

    def _position_threshold_changed(self):
        try:
            if int(self.position_threshold) < 0 or int(
                    self.position_threshold) > 1e6:
                self.position_threshold = str(0)
        except:
            self.position_threshold = str(0)
        self.settings_yaml.set_threshold_field('position',
                                               int(self.position_threshold))
        self.settings_yaml.dump()

    def _depth_threshold_changed(self):
        try:
            if int(self.depth_threshold) < 0 or int(
                    self.depth_threshold) > self.plot_history_max:
                self.plot_history_max = str(0)
        except:
            self.plot_history_max = str(0)
        self.settings_yaml.set_threshold_field('depth',
                                               int(self.depth_threshold))
        self.settings_yaml.dump()

    def _time_threshold_changed(self):
        try:
            if int(self.time_threshold) < 0:
                self.time_threshold = str(0)
        except:
            self.time_threshold = str(0)
        self.settings_yaml.set_threshold_field('time',
                                               int(self.time_threshold))
        self.settings_yaml.dump()

    def _focused_dev_changed(self):
        self.zoom_once = True

    def _zoomall_button_fired(self):
        self.zoomall = not self.zoomall

    def _paused_button_fired(self):
        self.running = not self.running

    def _clear_button_fired(self):
        self.neds[:] = np.NAN
        self.fixeds[:] = False
        self.devs[:] = 0
        self.times[:] = 0
        self.plot_data.set_data('n_fixed', [])
        self.plot_data.set_data('e_fixed', [])
        self.plot_data.set_data('d_fixed', [])
        self.plot_data.set_data('n_float', [])
        self.plot_data.set_data('e_float', [])
        self.plot_data.set_data('d_float', [])
        self.plot_data.set_data('n_satisfied', [])
        self.plot_data.set_data('e_satisfied', [])
        self.plot_data.set_data('n_focused', [])
        self.plot_data.set_data('e_focused', [])
        self.plot_data.set_data('t', [])

    def _baseline_callback_ned(self, sbp_msg, **metadata):
        # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
        # actually perform the update in the UI thread.
        if self.running:
            #GUI.invoke_later(self.baseline_callback, sbp_msg)

            soln = MsgBaselineNED(sbp_msg)
            GUI.invoke_later(self.baseline_callback, soln)

            cnt = self.cnt % 4
            fake_sbp_msg = copy.copy(soln)
            if cnt == 3:
                fake_sbp_msg.e = 217371
                fake_sbp_msg.n = 100837 - (cnt + 1) * 10e3
            else:
                fake_sbp_msg.e = 217371 + cnt * 20e3
                fake_sbp_msg.n = 100837 - cnt * 20e3
            fake_sbp_msg.sender = 100 + cnt
            fake_sbp_msg.flags = cnt
            soln = fake_sbp_msg
            self.cnt += 1
            GUI.invoke_later(self.baseline_callback, soln)

        # _threshold_satisfied()函数计算需要优化
        # 或者保持数据发送频率小于2(/s)
        time.sleep(0.5)

    def baseline_callback(self, sbp_msg):
        #soln = MsgBaselineNED(sbp_msg)
        soln = sbp_msg

        soln.n = soln.n * 1e-3
        soln.e = soln.e * 1e-3
        soln.d = soln.d * 1e-3

        dist = np.sqrt(soln.n**2 + soln.e**2 + soln.d**2)

        tow = soln.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        #row_data = [soln.sender, soln.n, soln.e, soln.d, soln.n_sats, soln.flags, soln.depth]
        row_data = [
            soln.sender, soln.n, soln.e, soln.d, soln.n_sats, soln.flags
        ]
        try:
            key = int(row_data[0])
            self.data_dict[key] = row_data
        except:
            pass
        self.utils.setDataViewTable(self.data_dict)
        if soln.sender not in self.dev_list:
            self.dev_list.append(soln.sender)
            self.dev_all_list.append(str(soln.sender))

        # Rotate array, deleting oldest entries to maintain
        # no more than N in plot
        self.neds[1:] = self.neds[:-1]
        self.fixeds[1:] = self.fixeds[:-1]
        self.devs[1:] = self.devs[:-1]
        self.times[1:] = self.times[:-1]

        # Insert latest position
        self.neds[0][:] = [soln.n, soln.e, soln.d]
        self.fixeds[0] = (soln.flags & 1) == 1
        self.devs[0] = int(soln.sender)
        self.times[0] = int(time.time())

        neds_all = []
        neds_fixed = []
        neds_float = []
        neds_satisfied = []
        neds_unsatisfied = []
        devs = np.unique(self.devs)
        if devs[0] == 0:
            devs = devs[1:]
        for dev in devs:
            is_dev = np.equal(dev, self.devs)
            neds_all.append(self.neds[is_dev][0])
            try:
                neds_fixed.append(self.neds[np.logical_and(
                    is_dev, self.fixeds)][0])
            except:
                pass
            try:
                neds_float.append(self.neds[np.logical_and(
                    is_dev, np.logical_not(self.fixeds))][0])
            except:
                pass
            position_satisfied, depth_satisfied, time_satisfied = self._threshold_satisfied(
            )
            is_satisfied = np.logical_and(position_satisfied, depth_satisfied,
                                          time_satisfied)
            try:
                neds_satisfied.append(self.neds[np.logical_and(
                    is_dev, is_satisfied)][0])
            except:
                pass
            try:
                neds_unsatisfied.append(self.neds[np.logical_and(
                    is_dev, np.logical_not(is_satisfied))][0])
            except:
                pass
        neds_all = np.array(neds_all)
        neds_fixed = np.array(neds_fixed)
        neds_float = np.array(neds_float)
        neds_satisfied = np.array(neds_satisfied)
        neds_unsatisfied = np.array(neds_unsatisfied)
        self.neds_all = neds_all
        self.neds_satisfied = neds_satisfied
        self.neds_unsatisfied = neds_unsatisfied

        neds_focused = np.empty((0, 3))
        if self.focused_dev == '':
            pass
        elif self.focused_dev == 'All':
            neds_focused = neds_all
        elif self.focused_dev != 'Preset':
            neds_focused = np.array(
                [self.neds[np.equal(self.devs, int(self.focused_dev))][0]])

        #if not all(map(any, np.isnan(neds_fixed))):
        if len(neds_fixed) > 0:
            self.plot_data.set_data('n_fixed', neds_fixed.T[0])
            self.plot_data.set_data('e_fixed', neds_fixed.T[1])
            self.plot_data.set_data('d_fixed', neds_fixed.T[2])
        #if not all(map(any, np.isnan(neds_float))):
        if len(neds_float) > 0:
            self.plot_data.set_data('n_float', neds_float.T[0])
            self.plot_data.set_data('e_float', neds_float.T[1])
            self.plot_data.set_data('d_float', neds_float.T[2])
        if len(neds_satisfied) > 0:
            self.plot_data.set_data('n_satisfied', neds_satisfied.T[0])
            self.plot_data.set_data('e_satisfied', neds_satisfied.T[1])
        if len(neds_unsatisfied) > 0:
            self.plot_data.set_data('n_unsatisfied', neds_unsatisfied.T[0])
            self.plot_data.set_data('e_unsatisfied', neds_unsatisfied.T[1])
        if len(self.presets) > 0:
            self.plot_data.set_data('n_preset', self.presets['n'])
            self.plot_data.set_data('e_preset', self.presets['e'])
        if len(neds_focused) > 0:
            self.plot_data.set_data('n_focused', neds_focused.T[0])
            self.plot_data.set_data('e_focused', neds_focused.T[1])

        if self.zoomall:
            self._zoomall()

        if self.zoom_once:
            if self.focused_dev == 'All':
                self._zoomall()
            elif self.focused_dev == 'Preset':
                plot_square_axes(self.plot, 'e_preset', 'n_preset')
            else:
                plot_square_axes(self.plot, 'e_focused', 'n_focused')
            self.zoom_once = False

    # 计算阈值,函数功能待测试
    def _threshold_satisfied(self):
        position_satisfieds = np.zeros(self.plot_history_max, dtype=bool)
        depth_satisfieds = np.ones(self.plot_history_max, dtype=bool)
        time_satisfieds = np.ones(self.plot_history_max, dtype=bool)

        devs = np.unique(self.devs)
        for dev in devs:
            dev_neds = self.neds[np.equal(self.devs, dev)]

            ned_mean = map(np.mean, zip(*dev_neds))
            dn = ned_mean[0] - self.presets['n']
            de = ned_mean[1] - self.presets['e']
            d = np.sqrt(np.add(np.square(dn), np.square(de)))
            dmin = np.min(d)
            if dmin < int(self.position_threshold):
                position_satisfieds[np.equal(dev, self.devs)] = True

        ne_depth = self.neds[0:int(self.depth_threshold)]
        for ned in ne_depth:
            dn = ned[0] - self.presets['n']
            de = ned[1] - self.presets['e']
            d = np.sqrt(np.add(np.square(dn), np.square(de)))
            dmin = np.min(d)
            if dmin > int(self.position_threshold):
                depth_satisfieds[np.equal(dev, self.devs)] = False
                break

        cur_time = time.time()
        for dev, t, ned in zip(self.devs, self.times, self.neds):
            dt = cur_time - t
            if dt > int(self.time_threshold):
                break
            dn = ned[0] - self.presets['n']
            de = ned[1] - self.presets['e']
            d = np.sqrt(np.add(np.square(dn), np.square(de)))
            dmin = np.min(d)
            if dmin > int(self.position_threshold):
                time_satisfieds[np.equal(dev, self.devs)] = False

        return (position_satisfieds, depth_satisfieds, time_satisfieds)

    def _zoomall(self):
        plot_square_axes(self.plot, ('e_fixed', 'e_float', 'e_preset'),
                         ('n_fixed', 'n_float', 'n_preset'))

    def _read_preset_points(self, filename='preset.csv'):
        preset_points = {}
        px = []
        py = []
        try:
            if os.path.isfile(filename):
                path_to_file = filename
            else:
                path_to_file = os.path.join(determine_path(), filename)
            f = open(path_to_file, 'r')
            for i in f.readlines():
                xy = i.split(',')
                if len(xy) < 2:
                    continue
                try:
                    x = float(xy[0]) * 1e-3
                    y = float(xy[1]) * 1e-3
                    px.append(x)
                    py.append(y)
                except:
                    continue
        except:
            pass
        preset_points['e'] = px
        preset_points['n'] = py
        return preset_points

    def set_utils(self, utils):
        self.utils = utils

    def __init__(self, link, plot_history_max=1000):
        super(BaselineView, self).__init__()
        self.plot_data = ArrayPlotData(n_fixed=[0.0],
                                       e_fixed=[0.0],
                                       d_fixed=[0.0],
                                       n_float=[0.0],
                                       e_float=[0.0],
                                       d_float=[0.0],
                                       n_satisfied=[0.0],
                                       e_satisfied=[0.0],
                                       n_unsatisfied=[0.0],
                                       e_unsatisfied=[0.0],
                                       n_focused=[0.0],
                                       e_focused=[0.0],
                                       t=[0.0],
                                       e_preset=[],
                                       n_preset=[])
        self.plot_history_max = plot_history_max

        self.neds = np.empty((plot_history_max, 3))
        self.neds[:] = np.NAN
        self.fixeds = np.zeros(plot_history_max, dtype=bool)
        self.devs = np.zeros(plot_history_max)
        self.times = np.zeros(plot_history_max)

        self.plot = Plot(self.plot_data)
        color_float = (0.5, 0.5, 1.0)
        color_fixed = 'orange'
        color_satisfied = (0.3, 1.0, 0.0)
        pts_float = self.plot.plot(('e_float', 'n_float'),
                                   type='scatter',
                                   color=color_float,
                                   marker='plus',
                                   line_width=2.0,
                                   marker_size=8.0)
        pts_fixed = self.plot.plot(('e_fixed', 'n_fixed'),
                                   type='scatter',
                                   color=color_fixed,
                                   marker='plus',
                                   line_width=2.0,
                                   marker_size=8.0)
        threshold_satisfied = self.plot.plot(('e_satisfied', 'n_satisfied'),
                                             type='scatter',
                                             color=color_satisfied,
                                             marker='dot',
                                             line_width=0.0,
                                             marker_size=4.5)
        threshold_unsatisfied = self.plot.plot(
            ('e_unsatisfied', 'n_unsatisfied'),
            type='scatter',
            color='red',
            marker='dot',
            line_width=0.0,
            marker_size=4.5)
        preset = self.plot.plot(('e_preset', 'n_preset'),
                                type='scatter',
                                color='black',
                                marker='plus',
                                marker_size=1.5,
                                line_width=0.0)
        pts_focused = self.plot.plot(('e_focused', 'n_focused'),
                                     type='scatter',
                                     color='black',
                                     marker='dot',
                                     line_width=0.0,
                                     marker_size=0.0)
        #plot_labels = ['RTK Fixed','RTK Float']
        #plots_legend = dict(zip(plot_labels, [pts_fixed, pts_float]))
        #self.plot.legend.plots = plots_legend
        #self.plot.legend.visible = True
        self.plot.legend.visible = False

        self.plot.index_axis.tick_label_position = 'inside'
        self.plot.index_axis.tick_label_color = 'gray'
        self.plot.index_axis.tick_color = 'gray'
        self.plot.index_axis.title = 'E (meters)'
        self.plot.index_axis.title_spacing = 5
        self.plot.value_axis.tick_label_position = 'inside'
        self.plot.value_axis.tick_label_color = 'gray'
        self.plot.value_axis.tick_color = 'gray'
        self.plot.value_axis.title = 'N (meters)'
        self.plot.value_axis.title_spacing = 5
        self.plot.padding = (25, 25, 25, 25)

        self.plot.tools.append(PanTool(self.plot))
        zt = ZoomTool(self.plot,
                      zoom_factor=1.1,
                      tool_mode="box",
                      always_on=False)
        self.plot.overlays.append(zt)

        self.week = None
        self.nsec = 0

        self.link = link
        self.link.add_callback(self._baseline_callback_ned,
                               SBP_MSG_BASELINE_NED)

        self.cnt = 0
        self.dev_list = []
        self.data_dict = {}
        self.presets = self._read_preset_points()

        self.settings_yaml = SettingsList()
        self.position_threshold = str(
            self.settings_yaml.get_threshold_field('position'))
        self.depth_threshold = str(
            self.settings_yaml.get_threshold_field('depth'))
        self.time_threshold = str(
            self.settings_yaml.get_threshold_field('time'))

        self.zoom_once = False

        self.python_console_cmds = {'baseline': self}
Пример #14
0
auto_survey_button = Action(name = "Auto Survey", action= "set_execute_callback_true", \
                              show_label=False)   

update_button = Action(name = "Update", action = "set_execute_callback_true", \
                             show_label=False)
reset_button = Action(name = "Reset", action = "set_execute_callback_true", \
                             show_label=False)
close_button = Action(name = "Close", action = "set_execute_callback_false", \
                             show_label=False)

from new import instancemethod

import sys, os
from pyface.image_resource import ImageResource
basedir = determine_path()
icon = ImageResource('icon',
         search_path=['images', os.path.join(basedir, 'images')])

# Handler methods that can be associated with buttons.
def set_execute_callback_true(self, info):
  info.object.execute_callback = True
  info.object.handler_executed = True

def set_execute_callback_false(self, info):
  info.object.execute_callback = False
  info.object.handler_executed = True

class CallbackHandler(Handler):

  # Register action handlers from passed list.
Пример #15
0
class SwiftConsole(HasTraits):
  """Traits-defined Swift Console.

  link : object
    Serial driver
  update : bool
    Update the firmware
  log_level_filter : str
    Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG".
  skip_settings : bool
    Don't read the device settings. Set to False when the console is reading
    from a network connection only.

  """

  link = Instance(sbpc.Handler)
  console_output = Instance(OutputList())
  python_console_env = Dict
  device_serial = Str('')
  a = Int
  b = Int
  tracking_view = Instance(TrackingView)
  solution_view = Instance(SolutionView)
  baseline_view = Instance(BaselineView)
  observation_view = Instance(ObservationView)
  networking_view = Instance(SbpRelayView)
  observation_view_base = Instance(ObservationView)
  system_monitor_view = Instance(SystemMonitorView)
  settings_view = Instance(SettingsView)
  update_view = Instance(UpdateView)
  log_level_filter = Enum(list(SYSLOG_LEVELS.itervalues()))

  paused_button = SVGButton(
    label='', tooltip='Pause console update', toggle_tooltip='Resume console update', toggle=True,
    filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'),
    toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'),
    width=8, height=8
  )
  clear_button = SVGButton(
    label='', tooltip='Clear console buffer',
    filename=os.path.join(determine_path(), 'images', 'iconic', 'x.svg'),
    width=8, height=8
  )

  view = View(
    VSplit(
      Tabbed(
        Item('tracking_view', style='custom', label='Tracking'),
        Item('solution_view', style='custom', label='Solution'),
        Item('baseline_view', style='custom', label='Baseline'),
        VSplit(
          Item('observation_view', style='custom', show_label=False),
          Item('observation_view_base', style='custom', show_label=False),
          label='Observations',
        ),
        Item('settings_view', style='custom', label='Settings'),
        Item('update_view', style='custom', label='Firmware Update'),
        Tabbed(
          Item('system_monitor_view', style='custom', label='System Monitor'),
          Item('networking_view', label='Networking', style='custom', show_label=False),
          Item(
            'python_console_env', style='custom',
            label='Python Console', editor=ShellEditor()),
          label='Advanced',
          show_labels=False
         ),
        show_labels=False
      ),
      VGroup(
        HGroup(
          Spring(width=4, springy=False),
          Item('paused_button', show_label=False, width=8, height=8),
          Item('clear_button', show_label=False, width=8, height=8),
          Item('', label='Console Log', emphasized=True),
          Spring(),
          UItem('log_level_filter', style='simple', padding=0, height=8, show_label=True,
                tooltip='Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.'),
        ),
        Item(
          'console_output',
          style='custom',
          editor=InstanceEditor(),
          height=0.3,
          show_label=False,
        ),
      )
    ),
    icon = icon,
    resizable = True,
    width = 1000,
    height = 600,
    handler = ConsoleHandler(),
    title = CONSOLE_TITLE
  )

  def print_message_callback(self, sbp_msg, **metadata):
    try:
      encoded = sbp_msg.payload.encode('ascii', 'ignore')
      for eachline in reversed(encoded.split('\n')):
        self.console_output.write_level(eachline,
                                        str_to_log_level(eachline.split(':')[0]))
    except UnicodeDecodeError:
      print "Critical Error encoding the serial stream as ascii."

  def log_message_callback(self, sbp_msg, **metadata):
    try:
      encoded = sbp_msg.text.encode('ascii', 'ignore')
      for eachline in reversed(encoded.split('\n')):
        self.console_output.write_level(eachline, sbp_msg.level)
    except UnicodeDecodeError:
      print "Critical Error encoding the serial stream as ascii."

  def ext_event_callback(self, sbp_msg, **metadata):
    e = MsgExtEvent(sbp_msg)
    print 'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s' % (
      "Rising" if (e.flags & (1<<0)) else "Falling", e.pin, e.wn, e.tow,
      "good" if (e.flags & (1<<1)) else "unknown")

  def _paused_button_fired(self):
    self.console_output.paused = not self.console_output.paused

  def _log_level_filter_changed(self):
    """
    Takes log level enum and translates into the mapped integer.
    Integer stores the current filter value inside OutputList.
    """
    self.console_output.log_level_filter = str_to_log_level(self.log_level_filter)

  def _clear_button_fired(self):
    self.console_output.clear()

  def __init__(self, link, update, log_level_filter, skip_settings=False, error=False):
    self.console_output = OutputList()
    self.console_output.write("Console: starting...")
    self.error = error
    sys.stdout = self.console_output
    if not error:
      sys.stderr = self.console_output
    self.log_level_filter = log_level_filter
    self.console_output.log_level_filter = str_to_log_level(log_level_filter)
    try:
      self.link = link
      self.link.add_callback(self.print_message_callback, SBP_MSG_PRINT_DEP)
      self.link.add_callback(self.log_message_callback, SBP_MSG_LOG)
      self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT)
      self.dep_handler = DeprecatedMessageHandler(link)
      settings_read_finished_functions = []
      self.tracking_view = TrackingView(self.link)
      self.solution_view = SolutionView(self.link)
      self.baseline_view = BaselineView(self.link)
      self.observation_view = ObservationView(self.link, name='Rover', relay=False)
      self.observation_view_base = ObservationView(self.link, name='Base', relay=True)
      self.system_monitor_view = SystemMonitorView(self.link)
      self.update_view = UpdateView(self.link, prompt=update)
      settings_read_finished_functions.append(self.update_view.compare_versions)
      self.networking_view = SbpRelayView(self.link)
      # Once we have received the settings, update device_serial with
      # the Piksi serial number which will be displayed in the window
      # title. This callback will also update the header route as used
      # by the networking view.
      def update_serial():
        serial_string = self.settings_view.settings['system_info']['serial_number'].value
        self.device_serial = 'PK%04d' % int(serial_string)
        if serial_string:
          self.networking_view.set_route(int(serial_string))
      settings_read_finished_functions.append(update_serial)
      self.settings_view = SettingsView(self.link,
                                        settings_read_finished_functions,
                                        skip=skip_settings)
      self.update_view.settings = self.settings_view.settings
      self.python_console_env = { 'send_message': self.link,
                                  'link': self.link, }
      self.python_console_env.update(self.tracking_view.python_console_cmds)
      self.python_console_env.update(self.solution_view.python_console_cmds)
      self.python_console_env.update(self.baseline_view.python_console_cmds)
      self.python_console_env.update(self.observation_view.python_console_cmds)
      self.python_console_env.update(self.networking_view.python_console_cmds)
      self.python_console_env.update(self.system_monitor_view.python_console_cmds)
      self.python_console_env.update(self.update_view.python_console_cmds)
      self.python_console_env.update(self.settings_view.python_console_cmds)
    except:
      import traceback
      traceback.print_exc()
      if self.error:
        sys.exit(1)
Пример #16
0
class BaselineView(HasTraits):
    python_console_cmds = Dict()

    table = List()

    logging_b = Bool(False)
    directory_name_b = File

    plot = Instance(Plot)
    plot_data = Instance(ArrayPlotData)

    running = Bool(True)
    zoomall = Bool(False)
    position_centered = Bool(False)

    clear_button = SVGButton(label='',
                             tooltip='Clear',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=16,
                             height=16)
    zoomall_button = SVGButton(label='',
                               tooltip='Zoom All',
                               toggle=True,
                               filename=os.path.join(determine_path(),
                                                     'images', 'iconic',
                                                     'fullscreen.svg'),
                               width=16,
                               height=16)
    center_button = SVGButton(label='',
                              tooltip='Center on Baseline',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'target.svg'),
                              width=16,
                              height=16)
    paused_button = SVGButton(label='',
                              tooltip='Pause',
                              toggle_tooltip='Run',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=16,
                              height=16)

    reset_button = Button(label='Reset Filters')
    reset_iar_button = Button(label='Reset IAR')
    init_base_button = Button(label='Init. with known baseline')

    traits_view = View(
        HSplit(
            Item('table',
                 style='readonly',
                 editor=TabularEditor(adapter=SimpleAdapter()),
                 show_label=False,
                 width=0.3),
            VGroup(
                HGroup(
                    Item('paused_button', show_label=False),
                    Item('clear_button', show_label=False),
                    Item('zoomall_button', show_label=False),
                    Item('center_button', show_label=False),
                    Item('reset_button', show_label=False),
                    Item('reset_iar_button', show_label=False),
                    Item('init_base_button', show_label=False),
                ),
                Item(
                    'plot',
                    show_label=False,
                    editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)),
                ))))

    def _zoomall_button_fired(self):
        self.zoomall = not self.zoomall

    def _center_button_fired(self):
        self.position_centered = not self.position_centered

    def _paused_button_fired(self):
        self.running = not self.running

    def _reset_button_fired(self):
        self.link(MsgResetFilters(filter=0))

    def _reset_iar_button_fired(self):
        self.link(MsgResetFilters(filter=1))

    def _init_base_button_fired(self):
        self.link(MsgInitBase())

    def _clear_button_fired(self):
        self.neds[:] = np.NAN
        self.fixeds[:] = False
        self.plot_data.set_data('n_fixed', [])
        self.plot_data.set_data('e_fixed', [])
        self.plot_data.set_data('d_fixed', [])
        self.plot_data.set_data('n_float', [])
        self.plot_data.set_data('e_float', [])
        self.plot_data.set_data('d_float', [])
        self.plot_data.set_data('t', [])
        self.plot_data.set_data('cur_fixed_n', [])
        self.plot_data.set_data('cur_fixed_e', [])
        self.plot_data.set_data('cur_fixed_d', [])
        self.plot_data.set_data('cur_float_n', [])
        self.plot_data.set_data('cur_float_e', [])
        self.plot_data.set_data('cur_float_d', [])

    def iar_state_callback(self, sbp_msg, **metadata):
        self.num_hyps = sbp_msg.num_hyps
        self.last_hyp_update = time.time()

    def _baseline_callback_ned(self, sbp_msg, **metadata):
        # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
        # actually perform the update in the UI thread.
        if self.running:
            GUI.invoke_later(self.baseline_callback, sbp_msg)

    def update_table(self):
        self._table_list = self.table.items()

    def gps_time_callback(self, sbp_msg, **metadata):
        self.week = MsgGPSTime(sbp_msg).wn
        self.nsec = MsgGPSTime(sbp_msg).ns

    def mode_string(self, msg):
        if msg:
            self.fixed = (msg.flags & 1) == 1
            if self.fixed:
                return 'Fixed RTK'
            else:
                return 'Float'
        return 'None'

    def baseline_callback(self, sbp_msg):
        self.last_btime_update = time.time()
        soln = MsgBaselineNED(sbp_msg)
        self.last_soln = soln
        table = []

        soln.n = soln.n * 1e-3
        soln.e = soln.e * 1e-3
        soln.d = soln.d * 1e-3

        dist = np.sqrt(soln.n**2 + soln.e**2 + soln.d**2)

        tow = soln.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        if self.week is not None:
            t = datetime.datetime(1980, 1, 6) + \
                datetime.timedelta(weeks=self.week) + \
                datetime.timedelta(seconds=tow)

            table.append(('GPS Time', t))
            table.append(('GPS Week', str(self.week)))

            if self.directory_name_b == '':
                filepath = time.strftime("baseline_log_%Y%m%d-%H%M%S.csv")
            else:
                filepath = os.path.join(
                    self.directory_name_b,
                    time.strftime("baseline_log_%Y%m%d-%H%M%S.csv"))

            if self.logging_b == False:
                self.log_file = None

            if self.logging_b:
                if self.log_file is None:
                    self.log_file = open(filepath, 'w')

                    self.log_file.write(
                        'time,north(meters),east(meters),down(meters),distance(meters),num_signals,flags,num_hypothesis\n'
                    )

                self.log_file.write('%s,%.4f,%.4f,%.4f,%.4f,%d,0x%02x,%d\n' %
                                    (str(t), soln.n, soln.e, soln.d, dist,
                                     soln.n_sats, soln.flags, self.num_hyps))
                self.log_file.flush()

        table.append(('GPS ToW', tow))

        table.append(('N', soln.n))
        table.append(('E', soln.e))
        table.append(('D', soln.d))
        table.append(('Dist.', dist))
        table.append(('Num. Signals.', soln.n_sats))
        table.append(('Flags', '0x%02x' % soln.flags))
        table.append(('Mode', self.mode_string(soln)))
        if time.time() - self.last_hyp_update < 10 and self.num_hyps != 1:
            table.append(('IAR Num. Hyps.', self.num_hyps))
        else:
            table.append(('IAR Num. Hyps.', "None"))

        # Rotate array, deleting oldest entries to maintain
        # no more than N in plot
        self.neds[1:] = self.neds[:-1]
        self.fixeds[1:] = self.fixeds[:-1]

        # Insert latest position
        self.neds[0][:] = [soln.n, soln.e, soln.d]
        self.fixeds[0] = self.fixed

        neds_fixed = self.neds[self.fixeds]
        neds_float = self.neds[np.logical_not(self.fixeds)]

        if not all(map(any, np.isnan(neds_fixed))):
            self.plot_data.set_data('n_fixed', neds_fixed.T[0])
            self.plot_data.set_data('e_fixed', neds_fixed.T[1])
            self.plot_data.set_data('d_fixed', neds_fixed.T[2])
        if not all(map(any, np.isnan(neds_float))):
            self.plot_data.set_data('n_float', neds_float.T[0])
            self.plot_data.set_data('e_float', neds_float.T[1])
            self.plot_data.set_data('d_float', neds_float.T[2])

        if self.fixed:
            self.plot_data.set_data('cur_fixed_n', [soln.n])
            self.plot_data.set_data('cur_fixed_e', [soln.e])
            self.plot_data.set_data('cur_fixed_d', [soln.d])
            self.plot_data.set_data('cur_float_n', [])
            self.plot_data.set_data('cur_float_e', [])
            self.plot_data.set_data('cur_float_d', [])
        else:
            self.plot_data.set_data('cur_float_n', [soln.n])
            self.plot_data.set_data('cur_float_e', [soln.e])
            self.plot_data.set_data('cur_float_d', [soln.d])
            self.plot_data.set_data('cur_fixed_n', [])
            self.plot_data.set_data('cur_fixed_e', [])
            self.plot_data.set_data('cur_fixed_d', [])

        self.plot_data.set_data('ref_n', [0.0])
        self.plot_data.set_data('ref_e', [0.0])
        self.plot_data.set_data('ref_d', [0.0])

        if self.position_centered:
            d = (self.plot.index_range.high - self.plot.index_range.low) / 2.
            self.plot.index_range.set_bounds(soln.e - d, soln.e + d)
            d = (self.plot.value_range.high - self.plot.value_range.low) / 2.
            self.plot.value_range.set_bounds(soln.n - d, soln.n + d)

        if self.zoomall:
            plot_square_axes(self.plot, ('e_fixed', 'e_float'),
                             ('n_fixed', 'n_float'))
        self.table = table

    def __init__(self, link, plot_history_max=1000, dirname=''):
        super(BaselineView, self).__init__()
        self.log_file = None
        self.directory_name_b = dirname
        self.num_hyps = 0
        self.last_hyp_update = 0
        self.last_btime_update = 0
        self.last_soln = None
        self.plot_data = ArrayPlotData(n_fixed=[0.0],
                                       e_fixed=[0.0],
                                       d_fixed=[0.0],
                                       n_float=[0.0],
                                       e_float=[0.0],
                                       d_float=[0.0],
                                       t=[0.0],
                                       ref_n=[0.0],
                                       ref_e=[0.0],
                                       ref_d=[0.0],
                                       cur_fixed_e=[],
                                       cur_fixed_n=[],
                                       cur_fixed_d=[],
                                       cur_float_e=[],
                                       cur_float_n=[],
                                       cur_float_d=[])
        self.plot_history_max = plot_history_max

        self.neds = np.empty((plot_history_max, 3))
        self.neds[:] = np.NAN
        self.fixeds = np.zeros(plot_history_max, dtype=bool)

        self.plot = Plot(self.plot_data)
        color_float = (0.5, 0.5, 1.0)
        color_fixed = 'orange'
        pts_float = self.plot.plot(('e_float', 'n_float'),
                                   type='scatter',
                                   color=color_float,
                                   marker='dot',
                                   line_width=0.0,
                                   marker_size=1.0)
        pts_fixed = self.plot.plot(('e_fixed', 'n_fixed'),
                                   type='scatter',
                                   color=color_fixed,
                                   marker='dot',
                                   line_width=0.0,
                                   marker_size=1.0)
        lin = self.plot.plot(('e_fixed', 'n_fixed'),
                             type='line',
                             color=(1, 0.65, 0, 0.1))
        ref = self.plot.plot(('ref_e', 'ref_n'),
                             type='scatter',
                             color='red',
                             marker='plus',
                             marker_size=5,
                             line_width=1.5)
        cur_fixed = self.plot.plot(('cur_fixed_e', 'cur_fixed_n'),
                                   type='scatter',
                                   color=color_fixed,
                                   marker='plus',
                                   marker_size=5,
                                   line_width=1.5)
        cur_float = self.plot.plot(('cur_float_e', 'cur_float_n'),
                                   type='scatter',
                                   color=color_float,
                                   marker='plus',
                                   marker_size=5,
                                   line_width=1.5)
        plot_labels = ['Base Position', 'RTK Fixed', 'RTK Float']
        plots_legend = dict(zip(plot_labels, [ref, cur_fixed, cur_float]))
        self.plot.legend.plots = plots_legend
        self.plot.legend.visible = True

        self.plot.index_axis.tick_label_position = 'inside'
        self.plot.index_axis.tick_label_color = 'gray'
        self.plot.index_axis.tick_color = 'gray'
        self.plot.index_axis.title = 'E (meters)'
        self.plot.index_axis.title_spacing = 5
        self.plot.value_axis.tick_label_position = 'inside'
        self.plot.value_axis.tick_label_color = 'gray'
        self.plot.value_axis.tick_color = 'gray'
        self.plot.value_axis.title = 'N (meters)'
        self.plot.value_axis.title_spacing = 5
        self.plot.padding = (25, 25, 25, 25)

        self.plot.tools.append(PanTool(self.plot))
        zt = ZoomTool(self.plot,
                      zoom_factor=1.1,
                      tool_mode="box",
                      always_on=False)
        self.plot.overlays.append(zt)

        self.week = None
        self.nsec = 0

        self.link = link
        self.link.add_callback(self._baseline_callback_ned,
                               SBP_MSG_BASELINE_NED)
        self.link.add_callback(self.iar_state_callback, SBP_MSG_IAR_STATE)
        self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME)

        self.python_console_cmds = {'baseline': self}
Пример #17
0
class ObservationView(HasTraits):
    python_console_cmds = Dict()

    _obs_table_list = List()
    obs = Dict()

    name = Str('Local')

    recording = Bool(False)

    record_button = SVGButton(
        label='Record',
        tooltip='Record Raw Observations',
        toggle_tooltip='Stop Recording',
        toggle=True,
        filename=os.path.join(determine_path(), 'images', 'fontawesome',
                              'floppy-o.svg'),
        toggle_filename=os.path.join(determine_path(), 'images', 'fontawesome',
                                     'stop.svg'),
        width=16,
        height=16)

    def trait_view(self, view):
        return View(
            HGroup(Item('_obs_table_list',
                        style='readonly',
                        editor=TabularEditor(adapter=SimpleAdapter()),
                        show_label=False),
                   VGroup(Item('record_button', show_label=False), ),
                   label=self.name,
                   show_border=True))

    def _record_button_fired(self):
        self.recording = not self.recording
        if not self.recording:
            if self.rinex_file is not None:
                self.rinex_file.close()
            self.rinex_file = None

    def rinex_save(self):
        if self.recording:
            if self.rinex_file is None:
                # If the file is being opened for the first time, write the RINEX header
                self.rinex_file = sopen(
                    os.path.join(
                        self.dirname,
                        self.name + self.t.strftime("-%Y%m%d-%H%M%S.obs")),
                    'w')
                header = '     ' +\
        """2.11           OBSERVATION DATA    G (GPS)             RINEX VERSION / TYPE
pyNEX                                   %s UTC PGM / RUN BY / DATE
                                                            MARKER NAME
                                                            OBSERVER / AGENCY
                                                            REC # / TYPE / VERS
                                                            ANT # / TYPE
   808673.9171 -4086658.5368  4115497.9775                  APPROX POSITION XYZ
        0.0000        0.0000        0.0000                  ANTENNA: DELTA H/E/N
     1     0                                                WAVELENGTH FACT L1/2
     3    C1    L1    S1                                    # / TYPES OF OBSERV
%s%13.7f     GPS         TIME OF FIRST OBS
                                                            END OF HEADER
""" % (
                    datetime.datetime.utcnow().strftime("%Y%m%d %H%M%S"),
                    self.t.strftime("  %Y    %m    %d    %H    %M"),
                                    self.t.second + self.t.microsecond * 1e-6)
                self.rinex_file.write(header)

            # L1CA only
            copy_prns = prns = [s for s in self.obs.iterkeys() if L1CA in s]
            self.rinex_file.write(
                "%s %10.7f  0 %2d" %
                (self.t.strftime(" %y %m %d %H %M"),
                 self.t.second + self.t.microsecond * 1e-6, len(prns)))

            while len(copy_prns) > 0:
                prns_ = copy_prns[:12]
                copy_prns = copy_prns[12:]
                for prn in prns_:
                    # take only the leading prn number
                    self.rinex_file.write('G%2d' % (int(prn.split()[0])))
                self.rinex_file.write('   ' * (12 - len(prns_)))
                self.rinex_file.write('\n')

            for prn in prns:
                # G    3 C1C L1C D1C
                self.rinex_file.write("%14.3f  " % self.obs[prn][0])
                self.rinex_file.write("%14.3f  " % self.obs[prn][1])
                self.rinex_file.write("%14.3f  \n" % self.obs[prn][2])

            self.rinex_file.flush()

    def update_obs(self):
        self._obs_table_list =\
          [(prn,) + obs for prn, obs in sorted(self.obs.items(),
                                               key=lambda x: x[0])]

    def obs_packed_callback(self, sbp_msg, **metadata):
        if (sbp_msg.sender is not None
                and (self.relay ^ (sbp_msg.sender == 0))):
            return
        tow = sbp_msg.header.t.tow
        wn = sbp_msg.header.t.wn
        seq = sbp_msg.header.n_obs

        tow = float(tow) / 1000.0

        total = seq >> 4
        count = seq & ((1 << 4) - 1)

        # Confirm this packet is good.
        # Assumes no out-of-order packets
        if count == 0:
            self.old_tow = self.gps_tow
            self.gps_tow = tow
            self.gps_week = wn
            self.prev_obs_total = total
            self.prev_obs_count = 0
            self.old_obs = copy.deepcopy(self.obs)
            self.obs = {}
        elif self.gps_tow != tow or\
             self.gps_week != wn or\
             self.prev_obs_count + 1 != count or\
             self.prev_obs_total != total:
            print "We dropped a packet. Skipping this observation sequence"
            self.prev_obs_count = -1
            return
        else:
            self.prev_obs_count = count

        # Save this packet
        # See sbp_piksi.h for format
        for o in sbp_msg.obs:
            prn = o.sid.sat
            # compute time difference of carrier phase for display
            cp = float(o.L.i) + float(o.L.f) / (1 << 8)
            if o.sid.code == 0 or o.sid.code == 1:
                prn += 1
            prn = '{} ({})'.format(prn, code_to_str(o.sid.code))
            if sbp_msg.msg_type == SBP_MSG_OBS_DEP_A or\
               sbp_msg.msg_type == SBP_MSG_OBS_DEP_B:
                divisor = 1e2
            else:
                divisor = 5e1
            try:
                ocp = self.old_obs[prn][1]
            except:
                ocp = 0
            cf = (cp - ocp) / (self.gps_tow - self.old_tow)
            self.obs[prn] = (float(o.P) / divisor,
                             float(o.L.i) + float(o.L.f) / (1 << 8),
                             float(o.cn0) / 4, cf)
        if (count == total - 1):
            self.t = datetime.datetime(1980, 1, 6) + \
                     datetime.timedelta(weeks=self.gps_week) + \
                     datetime.timedelta(seconds=self.gps_tow)

            self.update_obs()
            self.rinex_save()

        return

    def ephemeris_callback(self, m, **metadata):
        prn = m.common.sid.sat
        if m.common.sid.code == 0 or m.common.sid.code == 1:
            prn += 1
        if self.recording:
            if self.eph_file is None:
                self.eph_file = sopen(
                    os.path.join(
                        self.dirname,
                        self.name + self.t.strftime("-%Y%m%d-%H%M%S.eph")),
                    'w')
                header = "time, " \
                       + "tgd, " \
                       + "crs, crc, cuc, cus, cic, cis, " \
                       + "dn, m0, ecc, sqrta, omega0, omegadot, w, inc, inc_dot, " \
                       + "af0, af1, af2, " \
                       + "toe_tow, toe_wn, toc_tow, toc_wn, " \
                       + "valid, " \
                       + "healthy, " \
                       + "prn\n"
                self.eph_file.write(header)

            strout = "%s %10.7f" % (self.t.strftime(" %y %m %d %H %M"),
                                    self.t.second + self.t.microsecond * 1e-6)
            strout += "," + str([
                m.tgd, m.c_rs, m.c_rc, m.c_uc, m.c_us, m.c_ic, m.c_is, m.dn,
                m.m0, m.ecc, m.sqrta, m.omega0, m.omegadot, m.w, m.inc,
                m.inc_dot, m.af0, m.af1, m.af2, m.common.toe.tow,
                m.common.toe.wn, m.toc.tow, m.toc.wn, m.common.valid,
                m.common.health_bits, prn
            ])[1:-1] + "\n"
            self.eph_file.write(strout)
            self.eph_file.flush()

    def __init__(self, link, name='Local', relay=False, dirname=None):
        super(ObservationView, self).__init__()
        self.dirname = dirname
        self.obs_count = 0
        self.gps_tow = 0.0
        self.gps_week = 0
        self.relay = relay
        self.name = name
        self.rinex_file = None
        self.eph_file = None
        self.link = link
        self.link.add_callback(self.obs_packed_callback,
                               [SBP_MSG_OBS, SBP_MSG_OBS_DEP_B])
        self.link.add_callback(self.ephemeris_callback, SBP_MSG_EPHEMERIS_GPS)
        self.python_console_cmds = {'obs': self}
Пример #18
0
class BaselineView(HasTraits):

    # This mapping should match the flag definitions in libsbp for
    # the MsgBaselineNED message. While this isn't strictly necessary
    # it helps avoid confusion

    python_console_cmds = Dict()

    table = List()

    logging_b = Bool(False)
    directory_name_b = File

    plot = Instance(Plot)
    plot_data = Instance(ArrayPlotData)

    running = Bool(True)
    zoomall = Bool(False)
    position_centered = Bool(False)

    clear_button = SVGButton(label='',
                             tooltip='Clear',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=16,
                             height=16)
    zoomall_button = SVGButton(label='',
                               tooltip='Zoom All',
                               toggle=True,
                               filename=os.path.join(determine_path(),
                                                     'images', 'iconic',
                                                     'fullscreen.svg'),
                               width=16,
                               height=16)
    center_button = SVGButton(label='',
                              tooltip='Center on Baseline',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'target.svg'),
                              width=16,
                              height=16)
    paused_button = SVGButton(label='',
                              tooltip='Pause',
                              toggle_tooltip='Run',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=16,
                              height=16)

    reset_button = Button(label='Reset Filters')

    traits_view = View(
        HSplit(
            Item('table',
                 style='readonly',
                 editor=TabularEditor(adapter=SimpleAdapter()),
                 show_label=False,
                 width=0.3),
            VGroup(
                HGroup(
                    Item('paused_button', show_label=False),
                    Item('clear_button', show_label=False),
                    Item('zoomall_button', show_label=False),
                    Item('center_button', show_label=False),
                    Item('reset_button', show_label=False),
                ),
                Item(
                    'plot',
                    show_label=False,
                    editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)),
                ))))

    def _zoomall_button_fired(self):
        self.zoomall = not self.zoomall

    def _center_button_fired(self):
        self.position_centered = not self.position_centered

    def _paused_button_fired(self):
        self.running = not self.running

    def _reset_button_fired(self):
        self.link(MsgResetFilters(filter=0))

    def _reset_remove_current(self):
        self.plot_data.set_data('cur_fixed_n', [])
        self.plot_data.set_data('cur_fixed_e', [])
        self.plot_data.set_data('cur_fixed_d', [])
        self.plot_data.set_data('cur_float_n', [])
        self.plot_data.set_data('cur_float_e', [])
        self.plot_data.set_data('cur_float_d', [])
        self.plot_data.set_data('cur_dgnss_n', [])
        self.plot_data.set_data('cur_dgnss_e', [])
        self.plot_data.set_data('cur_dgnss_d', [])

    def _clear_button_fired(self):
        self.n[:] = np.NAN
        self.e[:] = np.NAN
        self.d[:] = np.NAN
        self.mode[:] = np.NAN
        self.plot_data.set_data('t', [])
        self.plot_data.set_data('n_fixed', [])
        self.plot_data.set_data('e_fixed', [])
        self.plot_data.set_data('d_fixed', [])
        self.plot_data.set_data('n_float', [])
        self.plot_data.set_data('e_float', [])
        self.plot_data.set_data('d_float', [])
        self.plot_data.set_data('n_dgnss', [])
        self.plot_data.set_data('e_dgnss', [])
        self.plot_data.set_data('d_dgnss', [])
        self._reset_remove_current()

    def iar_state_callback(self, sbp_msg, **metadata):
        self.num_hyps = sbp_msg.num_hyps
        self.last_hyp_update = time.time()

    def _baseline_callback_ned(self, sbp_msg, **metadata):
        # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
        # actually perform the update in the UI thread.
        if self.running:
            GUI.invoke_later(self.baseline_callback, sbp_msg)

    def update_table(self):
        self._table_list = list(self.table.items())

    def gps_time_callback(self, sbp_msg, **metadata):
        if sbp_msg.msg_type == SBP_MSG_GPS_TIME_DEP_A:
            time_msg = MsgGPSTimeDepA(sbp_msg)
            flags = 1
        elif sbp_msg.msg_type == SBP_MSG_GPS_TIME:
            time_msg = MsgGPSTime(sbp_msg)
            flags = time_msg.flags
            if flags != 0:
                self.week = time_msg.wn
                self.nsec = time_msg.ns

    def baseline_callback(self, sbp_msg):
        soln = MsgBaselineNEDDepA(sbp_msg)
        self.last_soln = soln
        table = []

        soln.n = soln.n * 1e-3
        soln.e = soln.e * 1e-3
        soln.d = soln.d * 1e-3
        soln.h_accuracy = soln.h_accuracy * 1e-3
        soln.v_accuracy = soln.v_accuracy * 1e-3

        dist = np.sqrt(soln.n**2 + soln.e**2 + soln.d**2)

        tow = soln.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        ((tloc, secloc), (tgps, secgps)) = log_time_strings(self.week, tow)

        if self.directory_name_b == '':
            filepath = time.strftime("baseline_log_%Y%m%d-%H%M%S.csv")
        else:
            filepath = os.path.join(
                self.directory_name_b,
                time.strftime("baseline_log_%Y%m%d-%H%M%S.csv"))

        if self.logging_b == False:
            self.log_file = None

        if self.logging_b:
            if self.log_file is None:
                self.log_file = sopen(filepath, 'w')
                self.log_file.write(
                    'pc_time,gps_time,tow(msec),north(meters),east(meters),down(meters),h_accuracy(meters),v_accuracy(meters),'
                    'distance(meters),num_sats,flags,num_hypothesis\n')
            log_str_gps = ''
            if tgps != '' and secgps != 0:
                log_str_gps = "{0}:{1:06.6f}".format(tgps, float(secgps))
            self.log_file.write(
                '%s,%s,%.3f,%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%d,%d,%d\n' %
                ("{0}:{1:06.6f}".format(tloc, float(secloc)), log_str_gps, tow,
                 soln.n, soln.e, soln.d, soln.h_accuracy, soln.v_accuracy,
                 dist, soln.n_sats, soln.flags, self.num_hyps))
            self.log_file.flush()

        self.last_mode = get_mode(soln)

        if self.last_mode < 1:
            table.append(('GPS Time', EMPTY_STR))
            table.append(('GPS Week', EMPTY_STR))
            table.append(('GPS TOW', EMPTY_STR))
            table.append(('N', EMPTY_STR))
            table.append(('E', EMPTY_STR))
            table.append(('D', EMPTY_STR))
            table.append(('h_accuracy', EMPTY_STR))
            table.append(('v_accuracy', EMPTY_STR))
            table.append(('Dist.', EMPTY_STR))
            table.append(('Num. Sats', EMPTY_STR))
            table.append(('Flags', EMPTY_STR))
            table.append(('Mode', EMPTY_STR))
        else:
            self.last_btime_update = time.time()
            if self.week is not None:
                table.append(
                    ('GPS Time', "{0}:{1:06.3f}".format(tgps, float(secgps))))
                table.append(('GPS Week', str(self.week)))
            table.append(('GPS TOW', "{:.3f}".format(tow)))
            table.append(('N', soln.n))
            table.append(('E', soln.e))
            table.append(('D', soln.d))
            table.append(('h_accuracy', soln.h_accuracy))
            table.append(('v_accuracy', soln.v_accuracy))
            table.append(('Dist.', dist))
            table.append(('Num. Sats', soln.n_sats))

        table.append(('Flags', '0x%02x' % soln.flags))
        table.append(('Mode', mode_dict[self.last_mode]))
        self.table = table
        # Rotate array, deleting oldest entries to maintain
        # no more than N in plot
        self.n[1:] = self.n[:-1]
        self.e[1:] = self.e[:-1]
        self.d[1:] = self.d[:-1]
        self.mode[1:] = self.mode[:-1]

        # Insert latest position
        if self.last_mode > 1:
            self.n[0], self.e[0], self.d[0] = soln.n, soln.e, soln.d
        else:
            self.n[0], self.e[0], self.d[0] = [np.NAN, np.NAN, np.NAN]
        self.mode[0] = self.last_mode

        if np.any(self.mode):
            float_indexer = (self.mode == FLOAT_MODE)
            fixed_indexer = (self.mode == FIXED_MODE)
            dgnss_indexer = (self.mode == DGNSS_MODE)

            if np.any(fixed_indexer):
                self.plot_data.set_data('n_fixed', self.n[fixed_indexer])
                self.plot_data.set_data('e_fixed', self.e[fixed_indexer])
                self.plot_data.set_data('d_fixed', self.d[fixed_indexer])
            if np.any(float_indexer):
                self.plot_data.set_data('n_float', self.n[float_indexer])
                self.plot_data.set_data('e_float', self.e[float_indexer])
                self.plot_data.set_data('d_float', self.d[float_indexer])
            if np.any(dgnss_indexer):
                self.plot_data.set_data('n_dgnss', self.n[dgnss_indexer])
                self.plot_data.set_data('e_dgnss', self.e[dgnss_indexer])
                self.plot_data.set_data('d_dgnss', self.d[dgnss_indexer])

            # Update our last solution icon
            if self.last_mode == FIXED_MODE:
                self._reset_remove_current()
                self.plot_data.set_data('cur_fixed_n', [soln.n])
                self.plot_data.set_data('cur_fixed_e', [soln.e])
                self.plot_data.set_data('cur_fixed_d', [soln.d])
            elif self.last_mode == FLOAT_MODE:
                self._reset_remove_current()
                self.plot_data.set_data('cur_float_n', [soln.n])
                self.plot_data.set_data('cur_float_e', [soln.e])
                self.plot_data.set_data('cur_float_d', [soln.d])
            elif self.last_mode == DGNSS_MODE:
                self._reset_remove_current()
                self.plot_data.set_data('cur_dgnss_n', [soln.n])
                self.plot_data.set_data('cur_dgnss_e', [soln.e])
                self.plot_data.set_data('cur_dgnss_d', [soln.d])
            else:
                pass
        # make the zoomall win over the position centered button
        # position centered button has no effect when zoom all enabled

        if not self.zoomall and self.position_centered:
            d = (self.plot.index_range.high - self.plot.index_range.low) / 2.
            self.plot.index_range.set_bounds(soln.e - d, soln.e + d)
            d = (self.plot.value_range.high - self.plot.value_range.low) / 2.
            self.plot.value_range.set_bounds(soln.n - d, soln.n + d)

        if self.zoomall:
            plot_square_axes(self.plot, ('e_fixed', 'e_float', 'e_dgnss'),
                             ('n_fixed', 'n_float', 'n_dgnss'))

    def __init__(self, link, plot_history_max=1000, dirname=''):
        super(BaselineView, self).__init__()
        self.log_file = None
        self.directory_name_b = dirname
        self.num_hyps = 0
        self.last_hyp_update = 0
        self.last_btime_update = 0
        self.last_soln = None
        self.last_mode = 0
        self.plot_data = ArrayPlotData(n_fixed=[0.0],
                                       e_fixed=[0.0],
                                       d_fixed=[0.0],
                                       n_float=[0.0],
                                       e_float=[0.0],
                                       d_float=[0.0],
                                       n_dgnss=[0.0],
                                       e_dgnss=[0.0],
                                       d_dgnss=[0.0],
                                       t=[0.0],
                                       ref_n=[0.0],
                                       ref_e=[0.0],
                                       ref_d=[0.0],
                                       cur_fixed_e=[],
                                       cur_fixed_n=[],
                                       cur_fixed_d=[],
                                       cur_float_e=[],
                                       cur_float_n=[],
                                       cur_float_d=[],
                                       cur_dgnss_e=[],
                                       cur_dgnss_n=[],
                                       cur_dgnss_d=[])

        self.plot_history_max = plot_history_max
        self.n = np.zeros(plot_history_max)
        self.e = np.zeros(plot_history_max)
        self.d = np.zeros(plot_history_max)
        self.mode = np.zeros(plot_history_max)

        self.plot = Plot(self.plot_data)
        pts_float = self.plot.plot(('e_float', 'n_float'),
                                   type='scatter',
                                   color=color_dict[FLOAT_MODE],
                                   marker='dot',
                                   line_width=0.0,
                                   marker_size=1.0)
        pts_fixed = self.plot.plot(('e_fixed', 'n_fixed'),
                                   type='scatter',
                                   color=color_dict[FIXED_MODE],
                                   marker='dot',
                                   line_width=0.0,
                                   marker_size=1.0)
        pts_dgnss = self.plot.plot(('e_dgnss', 'n_dgnss'),
                                   type='scatter',
                                   color=color_dict[DGNSS_MODE],
                                   marker='dot',
                                   line_width=0.0,
                                   marker_size=1.0)
        ref = self.plot.plot(('ref_e', 'ref_n'),
                             type='scatter',
                             color='red',
                             marker='plus',
                             marker_size=5,
                             line_width=1.5)
        cur_fixed = self.plot.plot(('cur_fixed_e', 'cur_fixed_n'),
                                   type='scatter',
                                   color=color_dict[FIXED_MODE],
                                   marker='plus',
                                   marker_size=5,
                                   line_width=1.5)
        cur_float = self.plot.plot(('cur_float_e', 'cur_float_n'),
                                   type='scatter',
                                   color=color_dict[FLOAT_MODE],
                                   marker='plus',
                                   marker_size=5,
                                   line_width=1.5)
        cur_dgnss = self.plot.plot(('cur_dgnss_e', 'cur_dgnss_n'),
                                   type='scatter',
                                   color=color_dict[DGNSS_MODE],
                                   marker='plus',
                                   line_width=1.5,
                                   marker_size=5)
        plot_labels = [' Base Position', 'DGPS', 'RTK Float', 'RTK Fixed']
        plots_legend = dict(
            list(zip(plot_labels, [ref, cur_dgnss, cur_float, cur_fixed])))
        self.plot.legend.plots = plots_legend
        self.plot.legend.labels = plot_labels  # sets order
        self.plot.legend.visible = True

        self.plot.index_axis.tick_label_position = 'inside'
        self.plot.index_axis.tick_label_color = 'gray'
        self.plot.index_axis.tick_color = 'gray'
        self.plot.index_axis.title = 'E (meters)'
        self.plot.index_axis.title_spacing = 5
        self.plot.value_axis.tick_label_position = 'inside'
        self.plot.value_axis.tick_label_color = 'gray'
        self.plot.value_axis.tick_color = 'gray'
        self.plot.value_axis.title = 'N (meters)'
        self.plot.value_axis.title_spacing = 5
        self.plot.padding = (25, 25, 25, 25)

        self.plot.tools.append(PanTool(self.plot))
        zt = ZoomTool(self.plot,
                      zoom_factor=1.1,
                      tool_mode="box",
                      always_on=False)
        self.plot.overlays.append(zt)

        self.week = None
        self.nsec = 0

        self.link = link
        self.link.add_callback(
            self._baseline_callback_ned,
            [SBP_MSG_BASELINE_NED, SBP_MSG_BASELINE_NED_DEP_A])
        self.link.add_callback(self.iar_state_callback, SBP_MSG_IAR_STATE)
        self.link.add_callback(self.gps_time_callback,
                               [SBP_MSG_GPS_TIME, SBP_MSG_GPS_TIME_DEP_A])

        self.python_console_cmds = {'baseline': self}
Пример #19
0
class SwiftConsole(HasTraits):
    """Traits-defined Swift Console.

  link : object
    Serial driver
  update : bool
    Update the firmware
  log_level_filter : str
    Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG".
  skip_settings : bool
    Don't read the device settings. Set to False when the console is reading
    from a network connection only.

  """

    link = Instance(sbpc.Handler)
    console_output = Instance(OutputList())
    python_console_env = Dict
    device_serial = Str('')
    a = Int
    b = Int
    tracking_view = Instance(TrackingView)
    solution_view = Instance(SolutionView)
    baseline_view = Instance(BaselineView)
    observation_view = Instance(ObservationView)
    networking_view = Instance(SbpRelayView)
    observation_view_base = Instance(ObservationView)
    system_monitor_view = Instance(SystemMonitorView)
    settings_view = Instance(SettingsView)
    update_view = Instance(UpdateView)
    log_level_filter = Enum(list(SYSLOG_LEVELS.itervalues()))
    """"
  mode : baseline and solution view - SPP, Fixed or Float
  num_sat : baseline and solution view - number of satellites
  port : which port is Piksi connected to
  directory_name : location of logged files
  json_logging : enable JSON logging
  csv_logging : enable CSV logging 
  is_valid_directory : check to see if chosen directory is valid

  """

    mode = Str('')
    num_sats = Int(0)
    port = Str('')
    directory_name = Directory
    json_logging = Bool(True)
    csv_logging = Bool(False)
    is_valid_directory = Bool(True)

    csv_logging_button = SVGButton(
        toggle=True,
        label='CSV log',
        tooltip='start CSV logging',
        toggle_tooltip='stop CSV logging',
        filename=os.path.join(determine_path(), 'images', 'iconic',
                              'pause.svg'),
        toggle_filename=os.path.join(determine_path(), 'images', 'iconic',
                                     'play.svg'),
        orientation='vertical',
        width=2,
        height=2,
    )
    json_logging_button = SVGButton(
        toggle=True,
        label='JSON log',
        tooltip='start JSON logging',
        toggle_tooltip='stop JSON logging',
        filename=os.path.join(determine_path(), 'images', 'iconic',
                              'pause.svg'),
        toggle_filename=os.path.join(determine_path(), 'images', 'iconic',
                                     'play.svg'),
        orientation='vertical',
        width=2,
        height=2,
    )
    paused_button = SVGButton(label='',
                              tooltip='Pause console update',
                              toggle_tooltip='Resume console update',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=8,
                              height=8)
    clear_button = SVGButton(label='',
                             tooltip='Clear console buffer',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=8,
                             height=8)

    view = View(VSplit(
        Tabbed(Item('tracking_view', style='custom', label='Tracking'),
               Item('solution_view', style='custom', label='Solution'),
               Item('baseline_view', style='custom', label='Baseline'),
               VSplit(
                   Item('observation_view', style='custom', show_label=False),
                   Item('observation_view_base',
                        style='custom',
                        show_label=False),
                   label='Observations',
               ),
               Item('settings_view', style='custom', label='Settings'),
               Item('update_view', style='custom', label='Firmware Update'),
               Tabbed(Item('system_monitor_view',
                           style='custom',
                           label='System Monitor'),
                      Item('networking_view',
                           label='Networking',
                           style='custom',
                           show_label=False),
                      Item('python_console_env',
                           style='custom',
                           label='Python Console',
                           editor=ShellEditor()),
                      label='Advanced',
                      show_labels=False),
               show_labels=False),
        VGroup(
            VGroup(
                HGroup(
                    Spring(width=4, springy=False),
                    Item('paused_button',
                         show_label=False,
                         padding=0,
                         width=8,
                         height=8),
                    Item('clear_button', show_label=False, width=8, height=8),
                    Item('', label='Console Log', emphasized=True),
                    Item('csv_logging_button',
                         emphasized=True,
                         show_label=False,
                         width=12,
                         height=-30,
                         padding=0),
                    Item('json_logging_button',
                         emphasized=True,
                         show_label=False,
                         width=12,
                         height=-30,
                         padding=0),
                    Item(
                        'directory_name',
                        show_label=False,
                        springy=True,
                        tooltip=
                        'Choose location for file logs. Default is home/SwiftNav.',
                        height=-25,
                        enabled_when='not(json_logging or csv_logging)'),
                    UItem(
                        'log_level_filter',
                        style='simple',
                        padding=0,
                        height=8,
                        show_label=True,
                        tooltip=
                        'Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.'
                    ),
                ),
                Item('console_output',
                     style='custom',
                     editor=InstanceEditor(),
                     height=125,
                     show_label=False,
                     full_size=True),
            ),
            HGroup(
                Spring(width=4, springy=False),
                Item('',
                     label='PORT:',
                     emphasized=True,
                     tooltip='Serial Port that Piksi is connected to'),
                Item('port', show_label=False, style='readonly'),
                Item('',
                     label='FIX TYPE:',
                     emphasized=True,
                     tooltip='Piksi Mode: SPS, Float RTK, Fixed RTK'),
                Item('mode', show_label=False, style='readonly'),
                Item('',
                     label='#SATS:',
                     emphasized=True,
                     tooltip='Number of satellites acquired by Piksi'),
                Item('num_sats', padding=2, show_label=False,
                     style='readonly'),
            ),
            Spring(height=1, springy=False),
        ),
    ),
                icon=icon,
                resizable=True,
                width=800,
                height=600,
                handler=ConsoleHandler(),
                title=CONSOLE_TITLE)

    def print_message_callback(self, sbp_msg, **metadata):
        try:
            encoded = sbp_msg.payload.encode('ascii', 'ignore')
            for eachline in reversed(encoded.split('\n')):
                self.console_output.write_level(
                    eachline, str_to_log_level(eachline.split(':')[0]))
        except UnicodeDecodeError:
            print "Critical Error encoding the serial stream as ascii."

    def log_message_callback(self, sbp_msg, **metadata):
        try:
            encoded = sbp_msg.text.encode('ascii', 'ignore')
            for eachline in reversed(encoded.split('\n')):
                self.console_output.write_level(eachline, sbp_msg.level)
        except UnicodeDecodeError:
            print "Critical Error encoding the serial stream as ascii."

    def ext_event_callback(self, sbp_msg, **metadata):
        e = MsgExtEvent(sbp_msg)
        print 'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s' % (
            "Rising" if
            (e.flags & (1 << 0)) else "Falling", e.pin, e.wn, e.tow, "good" if
            (e.flags & (1 << 1)) else "unknown")

    def _paused_button_fired(self):
        self.console_output.paused = not self.console_output.paused

    def _log_level_filter_changed(self):
        """
    Takes log level enum and translates into the mapped integer.
    Integer stores the current filter value inside OutputList.
    """
        self.console_output.log_level_filter = str_to_log_level(
            self.log_level_filter)

    def _clear_button_fired(self):
        self.console_output.clear()

    def _directory_name_changed(self):
        if os.path.isdir(self.directory_name):
            self.is_valid_directory = True
            if self.baseline_view and self.solution_view:
                self.baseline_view.directory_name_b = self.directory_name
                self.solution_view.directory_name_p = self.directory_name
                self.solution_view.directory_name_v = self.directory_name
            if self.observation_view and self.observation_view_base:
                self.observation_view.dirname = self.directory_name
                self.observation_view_base.dirname = self.directory_name
        else:
            print "Please enter a valid directory!"
            self.is_valid_directory = False

    def update_on_heartbeat(self, sbp_msg, **metadata):
        # First initialize the state to nothing, if we can't update, it will be none
        temp_mode = "None"
        temp_num_sats = 0
        view = None
        # If we have a recent baseline update, we use the baseline info
        if time.time() - self.baseline_view.last_btime_update < 10:
            view = self.baseline_view
        # Otherwise, if we have a recent SPP update, we use the SPP
        elif time.time() - self.solution_view.last_stime_update < 10:
            view = self.solution_view
        if view:
            if view.last_soln:
                # if all is well we update state
                temp_mode = view.mode_string(view.last_soln)
                temp_num_sats = view.last_soln.n_sats

        self.mode = temp_mode
        self.num_sats = temp_num_sats

        if self.settings_view:  # for auto populating surveyed fields
            self.settings_view.lat = self.solution_view.latitude
            self.settings_view.lon = self.solution_view.longitude
            self.settings_view.alt = self.solution_view.altitude

    def _csv_logging_button_fired(self):
        if self.is_valid_directory:
            if self.csv_logging and self.baseline_view.logging_b and self.solution_view.logging_p and self.solution_view.logging_v:
                print "Stopped CSV logging"
                self.csv_logging = False
                self.baseline_view.logging_b = False
                self.solution_view.logging_p = False
                self.solution_view.logging_v = False

            else:
                print "Started CSV logging at %s" % self.directory_name
                self.csv_logging = True
                self.baseline_view.logging_b = True
                self.solution_view.logging_p = True
                self.solution_view.logging_v = True
        else:
            print "Directory not valid"

    def _start_json_logging(self, override_filename=None):
        if override_filename:
            filename = override_filename
        else:
            filename = s.logfilename()
        filename = os.path.normpath(os.path.join(self.directory_name,
                                                 filename))
        self.logger = s.get_logger(True, filename)
        self.forwarder = sbpc.Forwarder(self.link, self.logger)
        self.forwarder.start()

    def _stop_json_logging(self):
        fwd = self.forwarder
        fwd.stop()
        self.logger.flush()
        self.logger.close()

    def _json_logging_button_fired(self):
        if self.is_valid_directory:
            if self.first_json_press and self.json_logging:
                print "JSON Logging initiated via CMD line.  Please press button again to stop logging"
            elif self.json_logging:
                self._stop_json_logging()
                self.json_logging = False
                print "Stopped JSON logging"
            else:
                self._start_json_logging()
                self.json_logging = True
            self.first_json_press = False
        else:
            print "Directory not valid"

    def __init__(self,
                 link,
                 update,
                 log_level_filter,
                 skip_settings=False,
                 error=False,
                 port=None,
                 json_logging=False,
                 log_dirname=None):
        self.console_output = OutputList()
        self.console_output.write("Console: starting...")
        self.error = error
        sys.stdout = self.console_output
        self.port = port
        self.num_sats = 0
        self.mode = ''
        self.forwarder = None
        # if we have passed a logfile, we set our directory to it
        override_filename = None
        swift_path = None
        home = expanduser("~")
        swift_path = os.path.normpath(os.path.join(home, 'SwiftNav'))
        try:
            os.makedirs(swift_path)
        except OSError:
            if not os.path.isdir(swift_path):
                raise

        if log_dirname:
            self.directory_name = log_dirname
        else:
            self.directory_name = swift_path

        if not error:
            sys.stderr = self.console_output
        self.log_level_filter = log_level_filter
        self.console_output.log_level_filter = str_to_log_level(
            log_level_filter)
        try:
            self.link = link
            self.link.add_callback(self.print_message_callback,
                                   SBP_MSG_PRINT_DEP)
            self.link.add_callback(self.log_message_callback, SBP_MSG_LOG)
            self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT)
            self.link.add_callback(self.update_on_heartbeat, SBP_MSG_HEARTBEAT)
            self.dep_handler = DeprecatedMessageHandler(link)
            settings_read_finished_functions = []
            self.tracking_view = TrackingView(self.link)
            self.solution_view = SolutionView(self.link,
                                              dirname=self.directory_name)
            self.baseline_view = BaselineView(self.link,
                                              dirname=self.directory_name)
            self.observation_view = ObservationView(
                self.link,
                name='Local',
                relay=False,
                dirname=self.directory_name)
            self.observation_view_base = ObservationView(
                self.link,
                name='Remote',
                relay=True,
                dirname=self.directory_name)
            self.system_monitor_view = SystemMonitorView(self.link)
            self.update_view = UpdateView(self.link, prompt=update)
            settings_read_finished_functions.append(
                self.update_view.compare_versions)
            self.networking_view = SbpRelayView(self.link)
            self.json_logging = json_logging
            self.csv_logging = False
            self.first_json_press = True
            if json_logging:
                self._start_json_logging(override_filename)
                self.json_logging = True

            # Once we have received the settings, update device_serial with
            # the Piksi serial number which will be displayed in the window
            # title. This callback will also update the header route as used
            # by the networking view.
            def update_serial():
                serial_string = self.settings_view.settings['system_info'][
                    'serial_number'].value
                self.device_serial = 'PK%04d' % int(serial_string)
                if serial_string:
                    self.networking_view.set_route(int(serial_string))

            settings_read_finished_functions.append(update_serial)
            self.settings_view = SettingsView(self.link,
                                              settings_read_finished_functions,
                                              skip=skip_settings)
            self.update_view.settings = self.settings_view.settings
            self.python_console_env = {
                'send_message': self.link,
                'link': self.link,
            }
            self.python_console_env.update(
                self.tracking_view.python_console_cmds)
            self.python_console_env.update(
                self.solution_view.python_console_cmds)
            self.python_console_env.update(
                self.baseline_view.python_console_cmds)
            self.python_console_env.update(
                self.observation_view.python_console_cmds)
            self.python_console_env.update(
                self.networking_view.python_console_cmds)
            self.python_console_env.update(
                self.system_monitor_view.python_console_cmds)
            self.python_console_env.update(
                self.update_view.python_console_cmds)
            self.python_console_env.update(
                self.settings_view.python_console_cmds)

        except:
            import traceback
            traceback.print_exc()
            if self.error:
                sys.exit(1)