def save(self, instance): def _do_save_config(filename): if not filename.endswith(RCP_CONFIG_FILE_EXTENSION): filename += RCP_CONFIG_FILE_EXTENSION with open(filename, 'w') as stream: configJson = self.rc_config.toJsonString() stream.write(configJson) self.set_config_file_path(instance.path) self.dismiss_popup() config_filename = instance.filename if len(config_filename): try: config_filename = os.path.join(instance.path, config_filename) if os.path.isfile(config_filename): def _on_answer(instance, answer): if answer: _do_save_config(config_filename) popup.dismiss() popup = confirmPopup('Confirm', 'File Exists - overwrite?', _on_answer) else: _do_save_config(config_filename) except Exception as detail: alertPopup('Error Saving', 'Failed to save:\n\n' + str(detail)) Logger.exception('ConfigView: Error Saving config: ' + str(detail))
def on_volts(self, mapBin, instance, focus_value): if not focus_value: value = instance.text.strip() if value == '' or value == "." or value == "-": value = 0 try: value = float(value) if self.scalingMap: self.scalingMap.setVolts(mapBin, value) self.dispatch('on_map_updated') self.regen_plot() except ScalingMapException as e: warn = CenteredBubble() warn.add_widget(WarnLabel(text=str(e))) warn.auto_dismiss_timeout(WARN_DISMISS_TIMEOUT) warn.background_color = (1, 0, 0, 1.0) warn.size = (dp(200), dp(50)) warn.size_hint = (None, None) self.get_root_window().add_widget(warn) warn.center_on(instance) original_value = self.scalingMap.getVolts(mapBin) self.set_volts_cell(instance, original_value) Clock.schedule_once(lambda dt: self._refocus(instance)) except Exception as e: alertPopup('Scaling Map', str(e)) original_value = self.scalingMap.getVolts(mapBin) self.set_volts_cell(instance, original_value)
def load_log(self): logpath = self._log_path session_name = self.ids.session_name.text.strip() session_notes = self.ids.session_notes.text.strip() if not os.path.isfile(logpath): alertPopup( "Invalid log specified", "Unable to find specified log file: {}. \nAre you sure it exists?" .format(logpath)) return Logger.info("LogImportWidget: loading log: {}".format( self.ids.log_path.text)) # choose a default name if the user deletes the suggested name if not session_name or len(session_name) == 0: session_name = self._extract_base_logfile_name(logpath) self.ids.session_name.text = session_name self.ids.current_status.text = "Initializing Datastore" self._set_form_disabled(True) t = Thread(target=self._loader_thread, args=(logpath, session_name, session_notes)) t.daemon = True t.start()
def on_volts(self, mapBin, instance): value = instance.text.strip() if value == '' or value == "." or value == "-": value = 0 instance.text = str(value) try: value = float(value) if self.scaling_map: self.scaling_map.setVolts(mapBin, value) self.dispatch('on_map_updated') self.regen_plot() except ScalingMapException as e: warn = CenteredBubble() warn.add_widget(WarnLabel(text=str(e))) warn.auto_dismiss_timeout(WARN_DISMISS_TIMEOUT) warn.background_color = (1, 0, 0, 1.0) warn.size = (dp(200), dp(50)) warn.size_hint = (None,None) self.get_root_window().add_widget(warn) warn.center_on(instance) original_value = self.scaling_map.getVolts(mapBin) self.set_volts_cell(instance, original_value) Clock.schedule_once(lambda dt: self._refocus(instance)) except Exception as e: alertPopup('Scaling Map', str(e)) original_value = self.scaling_map.getVolts(mapBin) self.set_volts_cell(instance, original_value)
def load_log(self): logpath = self._log_path session_name = self.ids.session_name.text.strip() session_notes = self.ids.session_notes.text.strip() dstore_path = self.settings.userPrefs.datastore_location if not os.path.isfile(logpath): alertPopup("Invalid log specified", "Unable to find specified log file: {}. \nAre you sure it exists?".format(logpath)) return if self.datastore.db_path != dstore_path: if self.datastore.is_open: self.datastore.close() if os.path.isfile(dstore_path): self.datastore.open_db(dstore_path) else: self.datastore.new(dstore_path) Logger.info("LogImportWidget: loading log: {}".format(self.ids.log_path.text)) # choose a default name if the user deletes the suggested name if not session_name or len(session_name) == 0: session_name = self._extract_base_logfile_name(logpath) self.ids.session_name.text = session_name self.ids.current_status.text = "Initializing Datastore" self._set_form_disabled(True) t = Thread(target=self._loader_thread, args=(logpath, session_name, session_notes)) t.daemon = True t.start()
def saveConfig(self): if self.rc_config.loaded: content = SaveDialog(ok=self.save, cancel=self.dismiss_popup, filters=['*' + RCP_CONFIG_FILE_EXTENSION], user_path=self.get_config_file_path()) self._popup = Popup(title="Save file", content=content, size_hint=(0.9, 0.9)) self._popup.open() else: alertPopup('Warning', 'Please load or read a configuration before saving')
def _add_unselected_channels(self, channels, source_ref): ProgressSpinner.increment_refcount() def get_results(results): # Auto-switch to time mode in charts only if the user # did not request it. if ( self.line_chart_mode == LineChartMode.DISTANCE and not self._results_has_distance(results) ): if self._user_refresh_requested == True: toast("Warning: one or more selected laps have missing distance data", length_long=True) self._user_refresh_requested = False else: self.line_chart_mode = LineChartMode.TIME self._refresh_chart_mode_toggle() # clone the incoming list of channels and pass it to the handler if self.line_chart_mode == LineChartMode.TIME: Clock.schedule_once(lambda dt: self._add_channels_results_time(channels[:], results)) elif self.line_chart_mode == LineChartMode.DISTANCE: Clock.schedule_once(lambda dt: self._add_channels_results_distance(channels[:], results)) else: Logger.error('LineChart: Unknown line chart mode ' + str(self.line_chart_mode)) try: self.datastore.get_channel_data(source_ref, ['Interval', 'Distance'] + channels, get_results) except Exception as e: alertPopup('Could not load lap', "There was a problem loading the lap due to missing data:\r\n\r\n{}".format(e)) raise # allow CrashHandler to record the issue finally: ProgressSpinner.decrement_refcount()
def delete_session(self, instance, id): try: self.datastore.delete_session(id) Logger.info('SessionBrowser: Session {} deleted'.format(id)) self.refresh_session_list() except DatastoreException as e: alertPopup('Error', 'There was an error deleting the session:\n{}'.format(e)) Logger.error('SessionBrowser: Error deleting session: {}\n\{}'.format(e, traceback.format_exc()))
def on_update_check_error(self, details): self.dismissPopups() Clock.schedule_once(lambda dt: self.refreshTrackList()) print('Error updating: ' + str(details)) alertPopup( 'Error Updating', 'There was an error updating the track list.\n\nPlease check your network connection and try again' )
def import_complete(self, instance, session_id, success, message): if success == True: self.dispatch('on_connect_stream_complete', session_id) return alertPopup("Import Failed", "There was a problem importing the datalog. Details:\n\n{}".format(message)) self.dispatch('on_connect_stream_complete', None)
def error(details): self.dismissPopups() Clock.schedule_once(lambda dt: self.refreshTrackList()) Logger.error('TracksBrowser: Error updating: {}'.format(details)) alertPopup( 'Error Updating', 'There was an error updating the track list.\n\nPlease check your network connection and try again' )
def _update_thread(self, instance): try: selection = instance.selection filename = selection[0] if len(selection) else None if filename: #Even though we stopped the RX thread, this is OK #since it doesn't return a value try: self.ids.fw_progress.title = "Processing" self._teardown_json_serial() except: import sys, traceback print "Exception in user code:" print '-' * 60 traceback.print_exc(file=sys.stdout) print '-' * 60 pass self.ids.fw_progress.title = "Progress" #Get our firmware updater class and register the #callback that will update the progress gauge fu = fw_update.FwUpdater() fu.register_progress_callback(self._update_progress_gauge) retries = 5 port = None while retries > 0 and not port: #Find our bootloader port = fu.scan_for_device() if not port: retries -= 1 sleep(2) if not port: self.ids.fw_progress.title = "" raise Exception("Unable to locate bootloader") #Go on our jolly way fu.update_firmware(filename, port) self.ids.fw_progress.title = "Restarting" #Windows workaround if platform == 'win': self.prompt_manual_restart() #Sleep for a few seconds since we need to let USB re-enumerate sleep(3) else: alertPopup('Error Loading', 'No firmware file selected') except Exception as detail: alertPopup('Error Loading', 'Failed to Load Firmware:\n\n' + str(detail)) if not platform == 'win': self._restart_json_serial() self.ids.fw_progress.value = '' self.ids.fw_progress.title = ""
def _update_thread(self, instance): try: selection = instance.selection filename = selection[0] if len(selection) else None if filename: #Even though we stopped the RX thread, this is OK #since it doesn't return a value try: self.ids.fw_progress.title="Processing" self._teardown_json_serial() except: import sys, traceback print "Exception in user code:" print '-'*60 traceback.print_exc(file=sys.stdout) print '-'*60 pass self.ids.fw_progress.title="Progress" #Get our firmware updater class and register the #callback that will update the progress gauge fu = fw_update.FwUpdater() fu.register_progress_callback(self._update_progress_gauge) retries = 5 port = None while retries > 0 and not port: #Find our bootloader port = fu.scan_for_device() if not port: retries -= 1 sleep(2) if not port: self.ids.fw_progress.title = "" raise Exception("Unable to locate bootloader") #Go on our jolly way fu.update_firmware(filename, port) self.ids.fw_progress.title = "Restarting" #Windows workaround if platform == 'win': self.prompt_manual_restart() #Sleep for a few seconds since we need to let USB re-enumerate sleep(3) else: alertPopup('Error Loading', 'No firmware file selected') except Exception as detail: alertPopup('Error Loading', 'Failed to Load Firmware:\n\n' + str(detail)) if not platform == 'win': self._restart_json_serial() self.ids.fw_progress.value = '' self.ids.fw_progress.title = ""
def _error(details): # do this in the UI thread popup.dismiss() Clock.schedule_once(lambda dt: self.refresh_view()) Logger.error( 'PresetBrowserView: Error updating: {}'.format(details)) alertPopup( 'Error Updating', 'There was an error updating the presets.\n\nPlease check your network connection and try again' )
def import_complete(self, instance, session_id, success, message): if success == True: self.dispatch('on_connect_stream_complete', session_id) return alertPopup( "Import Failed", "There was a problem importing the datalog. Details:\n\n{}".format( message)) self.dispatch('on_connect_stream_complete', None)
def _on_answer(instance, answer): if answer: session_name = session_editor.session_name if not session_name or len(session_name) == 0: alertPopup('Error', 'A session name must be specified') return session.name = session_editor.session_name session.notes = session_editor.session_notes self.datastore.update_session(session) self.refresh_session_list() popup.dismiss()
def _on_preferences_change(self, menu, config, section, key, value): """Called any time the app preferences are changed """ token = (section, key) if token == ('preferences', 'send_telemetry'): if value == "1": # Boolean settings values are 1/0, not True/False if self.rc_config.connectivityConfig.cellConfig.cellEnabled: alertPopup('Telemetry error', "Turn off RaceCapture's telemetry module for app to stream telemetry.") self._telemetry_connection.telemetry_enabled = True else: self._telemetry_connection.telemetry_enabled = False
def on_calibrate(self): # First check if config was updated and prompt stale = False for editor in self.editors: if editor.channelConfig.stale: stale = True if stale: alertPopup("Warning", "Accel configuration has been modified, write config first, then calibrate.") else: self.rc_api.calibrate_imu(self.on_calibrate_win, self.on_calibrate_fail)
def on_calibrate_win(self, result): alertPopup('Calibration', 'Calibration Complete') # Re-read just imu config def read_success(imu_cfg): self.imu_cfg.fromJson(imu_cfg['imuCfg']) self._update_view(self.imu_cfg) def read_fail(): Logger.error("ImuChannelsView: Failed to read imu cfg after calibration") self.rc_api.getImuCfg(None, read_success, read_fail)
def on_calibrate(self): # First check if config was updated and prompt stale = False for editor in self.editors: if editor.stale: stale = True if stale: alertPopup("Warning", "Configuration has been modified - please write configuration before calibrating.") else: self.rc_api.calibrate_imu(self.on_calibrate_win, self.on_calibrate_fail)
def _import_preset(self, id): try: preset = self.preset_manager.get_preset_by_id(id) if preset: mapping = preset.mapping for channel_json in mapping['chans']: new_channel = CANChannel() new_channel.from_json_dict(channel_json) self.add_can_channel(new_channel) self._refresh_channel_list_notice(self.can_channels_cfg) except Exception as e: alertPopup('Error', 'There was an error loading the preset:\n\n{}'.format(e)) raise
def delete_session(self, instance, id): self.deselect_laps(instance.get_all_laps()) try: self.datastore.delete_session(id) Logger.info('SessionBrowser: Session {} deleted'.format(id)) self.refresh_session_list() except DatastoreException as e: alertPopup( 'Error', 'There was an error deleting the session:\n{}'.format(e)) Logger.error( 'SessionBrowser: Error deleting session: {}\n\{}'.format( e, traceback.format_exc()))
def rc_detect_win(self, version): if version.is_compatible_version(): self.showStatus("{} v{}.{}.{}".format(version.friendlyName, version.major, version.minor, version.bugfix), False) self.dataBusPump.startDataPump(self._databus, self._rc_api) self._status_pump.start(self._rc_api) if self.rc_config.loaded == False: Clock.schedule_once(lambda dt: self.on_read_config(self)) else: self.showActivity('Connected') else: alertPopup('Incompatible Firmware', 'Detected {} v{}\n\nPlease upgrade firmware to {} or higher'.format( version.friendlyName, version.version_string(), VersionConfig.get_minimum_version().version_string() ))
def _update_thread(self, instance): try: selection = instance.selection filename = selection[0] if len(selection) else None if filename: # Even though we stopped the RX thread, this is OK # since it doesn't return a value self.ids.fw_progress.title = "Processing" self._teardown_json_serial() self.ids.fw_progress.title = "Progress" # Get our firmware updater class and register the # callback that will update the progress gauge fu = fw_update.FwUpdater(logger=Logger) fu.register_progress_callback(self._update_progress_gauge) retries = 5 port = None while retries > 0 and not port: # Find our bootloader port = fu.scan_for_device() if not port: retries -= 1 sleep(2) if not port: self.ids.fw_progress.title = "" raise Exception("Unable to locate bootloader") # Go on our jolly way fu.update_firmware(filename, port) self.ids.fw_progress.title = "Restarting" # Sleep for a few seconds since we need to let USB re-enumerate sleep(3) else: alertPopup('Error Loading', 'No firmware file selected') except Exception as detail: alertPopup('Error Loading', 'Failed to Load Firmware:\n\n{}'.format(detail)) Logger.error(traceback.format_exc()) self._restart_json_serial() self.ids.fw_progress.value = '' self.ids.fw_progress.title = ""
def _import_preset(self, id): try: preset = self.preset_manager.get_preset_by_id(id) if preset: mapping = preset.mapping for channel_json in mapping['pids']: new_channel = PidConfig() new_channel.fromJson(channel_json) self.obd2_cfg.pids.append(new_channel) self.reload_obd2_channel_grid(self.obd2_cfg) self.obd2_cfg.stale = True self.dispatch('on_modified') self._refresh_channel_list_notice(self.obd2_cfg) except Exception as e: alertPopup('Error', 'There was an error loading the preset:\n\n{}'.format(e)) raise
def on_calibrate(self): # First check if config was updated and prompt stale = False for editor in self.editors: if editor.stale: stale = True if stale: alertPopup( "Warning", "Configuration has been modified - please write configuration before calibrating." ) else: self.rc_api.calibrate_imu(self.on_calibrate_win, self.on_calibrate_fail)
def _on_answer(instance, answer): if answer: session_name = session_editor.session_name if not session_name or len(session_name) == 0: alertPopup('Error', 'A session name must be specified') return # did the session name change? if so, refresh the view. new_name = session_editor.session_name if new_name != session.name: session.name = new_name session_accordion = self._find_session_accordion_item(session) session_accordion.title = new_name session.notes = session_editor.session_notes self.datastore.update_session(session) self.dispatch('on_session_updated', session) popup.dismiss()
def _on_preference_change(self, instance, section, key, value): """Called any time the app preferences are changed """ token = (section, key) if token == ('preferences', 'send_telemetry'): if value == "1": # Boolean settings values are 1/0, not True/False if self.rc_config.connectivityConfig.cellConfig.cellEnabled: alertPopup('Telemetry error', "Disable the telemetry module before enabling app telemetry.") Clock.schedule_once(lambda dt: self._enable_telemetry()) else: Clock.schedule_once(lambda dt: self._disable_telemetry()) if token == ('preferences', 'conn_type'): # User changed their RC connection type Logger.info("RaceCaptureApp: RC connection type changed to {}, restarting comms".format(value)) Clock.schedule_once(lambda dt: self._restart_comms())
def rc_detect_win(self, version): if version.is_compatible_version(): self.showStatus( "{} v{}.{}.{}".format(version.friendlyName, version.major, version.minor, version.bugfix), False) self.dataBusPump.startDataPump(self._databus, self._rc_api) self._status_pump.start(self._rc_api) if self.rc_config.loaded == False: Clock.schedule_once(lambda dt: self.on_read_config(self)) else: self.showActivity('Connected') else: alertPopup( 'Incompatible Firmware', 'Detected {} v{}\n\nPlease upgrade firmware to {} or higher'. format(version.friendlyName, version.version_string(), VersionConfig.get_minimum_version().version_string()))
def rc_detect_win(self, version): if version.is_compatible_version(): version_string = version.git_info if version.git_info is not '' else 'v' + version.version_string() self.showStatus("{} {}".format(version.friendlyName, version_string), False) self._data_bus_pump.start(self._databus, self._rc_api, self._session_recorder, self._rc_api.comms.supports_streaming) self._status_pump.start(self._rc_api) self._telemetry_connection.data_connected = True if self.rc_config.loaded == False: Clock.schedule_once(lambda dt: self.on_read_config(self)) else: self.showActivity('Connected') else: alertPopup('Incompatible Firmware', 'Detected {} v{}\n\nPlease upgrade firmware to {} or higher'.format( version.friendlyName, version.version_string(), VersionConfig.get_minimum_version().version_string() ))
def load(self, instance): self.set_config_file_path(instance.path) self.dismiss_popup() try: selection = instance.selection filename = selection[0] if len(selection) else None if filename: with open(filename) as stream: rcpConfigJsonString = stream.read() self.rc_config.fromJsonString(rcpConfigJsonString) self.rc_config.stale = True self.update_config_views() self.on_config_modified() else: alertPopup('Error Loading', 'No config file selected') except Exception as detail: alertPopup('Error Loading', 'Failed to Load Configuration:\n\n' + str(detail)) Logger.exception('ConfigView: Error loading config: ' + str(detail))
def show_node(node): try: view = node.view if not view: view = node.view_builder() self.configViews.append(view) view.bind(on_config_modified=self.on_config_modified) node.view = view if self.loaded: if self.rc_config: view.dispatch('on_config_updated', self.rc_config) if self.track_manager: view.dispatch('on_tracks_updated', self.track_manager) Clock.schedule_once(lambda dt: self.ids.content.add_widget(view)) except Exception as detail: alertPopup('Error', 'Error loading screen ' + str(node.text) + ':\n\n' + str(detail)) Logger.error("ConfigView: Error selecting configuration view " + str(node.text))
def on_tracks_selected(self, instance, selectedTrackIds): if self.trackDb: failures = False for trackId in selectedTrackIds: trackMap = self.track_manager.get_track_by_id(trackId) if trackMap: startFinish = trackMap.start_finish_point if startFinish and startFinish.latitude and startFinish.longitude: Logger.info("TrackConfigView: adding track " + str(trackMap)) track = Track.fromTrackMap(trackMap) self.trackDb.tracks.append(track) else: failures = True if failures: alertPopup('Cannot Add Tracks', 'One or more tracks could not be added due to missing start/finish points.\n\nPlease check for track map updates and try again.') self.init_tracks_list() self.trackSelectionPopup.dismiss() self.trackDb.stale = True self.dispatch('on_modified')
def rc_detect_win(self, version): if version.is_compatible_version(): self.showStatus("{} v{}.{}.{}".format(version.friendlyName, version.major, version.minor, version.bugfix), False) self._data_bus_pump.start(self._databus, self._rc_api) self._status_pump.start(self._rc_api) if self.settings.userPrefs.get_pref('preferences', 'send_telemetry') == "1" and self._telemetry_connection: self._telemetry_connection.telemetry_enabled = True if self.rc_config.loaded == False: Clock.schedule_once(lambda dt: self.on_read_config(self)) else: self.showActivity('Connected') else: alertPopup('Incompatible Firmware', 'Detected {} v{}\n\nPlease upgrade firmware to {} or higher'.format( version.friendlyName, version.version_string(), VersionConfig.get_minimum_version().version_string() ))
def on_tracks_selected(self, instance, selectedTrackIds): if self.trackDb: failures = False for trackId in selectedTrackIds: trackMap = self.track_manager.getTrackById(trackId) if trackMap: startFinish = trackMap.startFinishPoint if startFinish and startFinish.latitude and startFinish.longitude: track = Track.fromTrackMap(trackMap) self.trackDb.tracks.append(track) else: failures = True if failures: alertPopup( 'Cannot Add Tracks', 'One or more tracks could not be added due to missing start/finish points.\n\nPlease check for track map updates and try again.' ) self.init_tracks_list() self.trackSelectionPopup.dismiss() self.trackDb.stale = True self.dispatch('on_modified')
def _add_unselected_channels(self, channels, source_ref): ProgressSpinner.increment_refcount() def get_results(results): # Auto-switch to time mode in charts only if the user # did not request it. if (self.line_chart_mode == LineChartMode.DISTANCE and not self._results_has_distance(results)): if self._user_refresh_requested == True: toast( "Warning: one or more selected laps have missing distance data", length_long=True) self._user_refresh_requested = False else: self.line_chart_mode = LineChartMode.TIME self._refresh_chart_mode_toggle() # clone the incoming list of channels and pass it to the handler if self.line_chart_mode == LineChartMode.TIME: Clock.schedule_once(lambda dt: self._add_channels_results_time( channels[:], results)) elif self.line_chart_mode == LineChartMode.DISTANCE: Clock.schedule_once( lambda dt: self._add_channels_results_distance( channels[:], results)) else: Logger.error('LineChart: Unknown line chart mode ' + str(self.line_chart_mode)) try: self.datastore.get_channel_data( source_ref, ['Interval', 'Distance'] + channels, get_results) except Exception as e: alertPopup( 'Could not load lap', "There was a problem loading the lap due to missing data:\r\n\r\n{}" .format(e)) raise # allow CrashHandler to record the issue finally: ProgressSpinner.decrement_refcount()
def on_tracks_selected(instance, selected_track_ids): if self.track_db: failures = False for trackId in selected_track_ids: trackMap = self.track_manager.get_track_by_id(trackId) if trackMap: startFinish = trackMap.start_finish_point if startFinish and startFinish.latitude and startFinish.longitude: Logger.info("TrackConfigView: adding track " + str(trackMap)) track = Track.fromTrackMap(trackMap) self.track_db.tracks.append(track) else: failures = True if failures: alertPopup( 'Cannot Add Tracks', 'One or more tracks could not be added due to missing start/finish points.\n\nPlease check for track map updates and try again.' ) self.init_tracks_list() popup.dismiss() self.track_db.stale = True self.dispatch('on_modified')
def on_write_config_error(self, detail): alertPopup('Error Writing', 'Could not write configuration:\n\n' + str(detail))
def _serial_warning(self): alertPopup( 'Warning', 'Command failed. Ensure you have selected a correct serial port')
def loadCurrentTracksError(self, details): alertPopup('Error Loading Tracks', str(details))
def _serial_warning(self): alertPopup('Warning', 'Command failed. Ensure you have selected a correct serial port')
def on_set_logfile_level_error(self, detail): alertPopup('Error', 'Error Setting Logfile Level:\n\n' + str(detail))
def on_read_config_error(self, detail): alertPopup('Error Reading', 'Could not read configuration:\n\n' + str(detail))
def on_run_script_error(self, detail): alertPopup('Error Running', 'Error Running Script:\n\n' + str(detail))