class MobilinkdTnc1Config(object): def __init__(self): self.tnc = None self.connect_message = None self.builder = Gtk.Builder() self.builder.add_from_file( os.path.join(glade_location(), "glade/MobilinkdTnc1Config.glade")) self.window = self.builder.get_object("window") self.window.connect("delete-event", self.close) self.init_serial_port_combobox() self.init_power_section() self.init_transmit_volume() self.init_receive_volume() self.init_kiss_parameters() self.init_firmware_section() self.init_eeprom_section() self.status = self.builder.get_object("statusbar") self.builder.connect_signals(self) self.tnc_disconnect() self.window.show() Gtk.main() def close(self, widget, data=None): if self.tnc is not None: self.tnc.disconnect() self.tnc = None Gtk.main_quit() def init_serial_port_combobox(self): self.serial_port_combobox = self.builder.get_object("serial_port_combobox") for port in comports(): self.serial_port_combobox.append_text(port[0]) def on_serial_port_combobox_changed(self, widget, data=None): text = widget.get_active_text() if text != None: self.tnc = TncModel(self, text) def init_power_section(self): self.battery_level_label = self.builder.get_object("battery_level_label") self.battery_level_bar = self.builder.get_object("battery_level_bar") self.battery_level_bar.set_fraction(0.0) self.power_control_box = self.builder.get_object("power_control_box") self.usb_on_button = self.builder.get_object("usb_on_button") self.usb_off_button = self.builder.get_object("usb_off_button") self.usb_on_button.set_sensitive(False) self.usb_off_button.set_sensitive(False) def init_eeprom_section(self): self.eeprom_frame = self.builder.get_object("eeprom_frame") self.eeprom_save_button = self.builder.get_object("eeprom_save_button") self.eeprom_save_button.set_sensitive(False) self.eeprom_frame.set_visible(False) def init_transmit_volume(self): self.transmit_volume_scale = self.builder.get_object("transmit_volume_scale") self.transmit_volume_scale.set_range(16.0, 255.0) self.transmit_volume_scale.set_value(128.0) self.transmit_volume_scale.set_sensitive(False) self.mark_toggle_button = self.builder.get_object("mark_toggle_button") self.space_toggle_button = self.builder.get_object("space_toggle_button") self.ptt_toggle_button = self.builder.get_object("ptt_toggle_button") def on_mark_toggle_button_toggled(self, widget, data=None): self.tnc.set_mark(widget.get_active()) def on_space_toggle_button_toggled(self, widget, data=None): self.tnc.set_space(widget.get_active()) def on_ptt_toggle_button_toggled(self, widget, data=None): self.tnc.set_ptt(widget.get_active()) def on_input_atten_toggle_button_toggled(self, widget, data=None): self.tnc.set_input_atten(widget.get_active()) def on_transmit_volume_scale_change_value(self, widget, scroll, value, data=None): if value > 255: value = 255 if value < 0: value = 0 widget.set_value(int(value)) self.tnc.set_tx_volume(int(value)) return True def init_receive_volume(self): self.receive_volume_levelbar = self.builder.get_object("receive_volume_levelbar") self.receive_volume_levelbar.add_offset_value(Gtk.LEVEL_BAR_OFFSET_LOW, 5.0) self.receive_volume_levelbar.add_offset_value(Gtk.LEVEL_BAR_OFFSET_HIGH, 7.0) self.receive_volume_levelbar.set_value(0.0) self.input_atten_toggle_button = self.builder.get_object("input_atten_toggle_button") self.receive_volume_progressbar = self.builder.get_object("receive_volume_progressbar") if os.name != "posix": self.receive_volume_progressbar.show() self.receive_volume_levelbar.hide() self.receive_volume_progressbar.set_fraction(0.0) def init_kiss_parameters(self): self.dcd_toggle_button = self.builder.get_object("dcd_toggle_button") self.kiss_tx_delay_spin_button = self.builder.get_object("kiss_tx_delay_spin_button") self.kiss_tx_delay_spin_button.set_range(0.0, 255.0) self.kiss_tx_delay_spin_button.set_increments(1.0, 10.0) self.kiss_tx_delay_spin_button.set_value(50) self.kiss_persistence_spin_button = self.builder.get_object("kiss_persistence_spin_button") self.kiss_persistence_spin_button.set_range(0.0, 255.0) self.kiss_persistence_spin_button.set_increments(1.0, 10.0) self.kiss_persistence_spin_button.set_value(63) self.kiss_slot_time_spin_button = self.builder.get_object("kiss_slot_time_spin_button") self.kiss_slot_time_spin_button.set_range(0.0, 255.0) self.kiss_slot_time_spin_button.set_increments(1.0, 10.0) self.kiss_slot_time_spin_button.set_value(25) self.kiss_tx_tail_spin_button = self.builder.get_object("kiss_tx_tail_spin_button") self.kiss_tx_tail_spin_button.set_range(0.0, 255.0) self.kiss_tx_tail_spin_button.set_increments(1.0, 10.0) self.kiss_tx_tail_spin_button.set_value(2) self.kiss_duplex_toggle_button = self.builder.get_object("kiss_duplex_toggle_button") self.kiss_full_duplex_image = self.builder.get_object("kiss_full_duplex_image") self.kiss_half_duplex_image = self.builder.get_object("kiss_half_duplex_image") self.conn_track_toggle_button = self.builder.get_object("conn_track_toggle_button") self.verbose_toggle_button = self.builder.get_object("verbose_toggle_button") self.ptt_label = self.builder.get_object("ptt_label") self.ptt_simplex_radiobutton = self.builder.get_object("ptt_simplex_radiobutton") self.ptt_multiplex_radiobutton = self.builder.get_object("ptt_multiplex_radiobutton") def on_dcd_toggled(self, widget, data=None): self.tnc.set_squelch_level((not widget.get_active()) * 2) def on_ptt_toggled(self, widget, data=None): if widget.get_active(): self.tnc.set_ptt_channel(self.ptt_multiplex_radiobutton.get_active()) def on_verbose_toggled(self, widget, data=None): self.tnc.set_verbosity(widget.get_active()) def on_kiss_duplex_toggled(self, widget, data=None): self.tnc.set_duplex(widget.get_active()) def on_conn_track_toggled(self, widget, data=None): self.tnc.set_conn_track(widget.get_active()) def on_kiss_tx_delay_spin_button_value_changed(self, widget, data=None): self.tnc.set_tx_delay(widget.get_value_as_int()) def on_kiss_persistence_spin_button_value_changed(self, widget, data=None): self.tnc.set_persistence(widget.get_value_as_int()) def on_kiss_slot_time_spin_button_value_changed(self, widget, data=None): self.tnc.set_time_slot(widget.get_value_as_int()) def on_kiss_tx_tail_spin_button_value_changed(self, widget, data=None): self.tnc.set_tx_tail(widget.get_value_as_int()) def on_connect_button_clicked(self, widget, data=None): if self.tnc is None: self.connect_message = self.status.push(1, "Please choose a serial port.") return if self.tnc.connected(): self.connect_message = self.status.push(1, "Already connected.") return if self.connect_message is not None: self.status.remove(1, self.connect_message) self.tnc.connect() def on_window_destroy(self, widget, data=None): print "quitting" Gtk.main_quit() def init_firmware_section(self): self.firmware_file_chooser_button = self.builder.get_object("firmware_file_chooser_button") self.upload_button = self.builder.get_object("upload_button") self.firmware_entry = self.builder.get_object("firmware_entry") def on_firmware_file_chooser_button_file_set(self, widget, data=None): self.firmware_file = self.firmware_file_chooser_button.get_filename() self.upload_button.set_sensitive(True) def on_eeprom_save_button_clicked(self, widget, data=None): self.tnc.save_eeprom_settings() def on_usb_on_button_toggled(self, widget, data=None): self.tnc.set_usb_on(widget.get_active()) def on_usb_off_button_toggled(self, widget, data=None): self.tnc.set_usb_off(widget.get_active()) def on_upload_button_clicked(self, widget, data=None): self.firmware_gui = FirmwareUploadGui(self.builder, self.tnc) self.tnc.upload_firmware(self.firmware_file, self.firmware_gui) self.firmware_gui_tag = GObject.idle_add(self.check_firmware_upload_complete) def tnc_connect(self): self.serial_port_combobox.set_sensitive(False) self.transmit_volume_scale.set_sensitive(True) self.mark_toggle_button.set_sensitive(True) self.mark_toggle_button.set_active(False) self.space_toggle_button.set_sensitive(True) self.space_toggle_button.set_active(False) self.ptt_toggle_button.set_sensitive(True) self.ptt_toggle_button.set_active(False) self.dcd_toggle_button.set_sensitive(False) self.dcd_toggle_button.set_active(False) self.verbose_toggle_button.set_sensitive(False) self.verbose_toggle_button.set_active(False) self.kiss_tx_delay_spin_button.set_sensitive(True) self.kiss_persistence_spin_button.set_sensitive(True) self.kiss_slot_time_spin_button.set_sensitive(True) self.kiss_tx_tail_spin_button.set_sensitive(True) self.kiss_duplex_toggle_button.set_sensitive(False) self.kiss_duplex_toggle_button.set_active(False) self.conn_track_toggle_button.set_sensitive(False) self.conn_track_toggle_button.set_active(False) self.firmware_file_chooser_button.set_sensitive(True) self.upload_button.set_sensitive(False) self.firmware_entry.set_sensitive(True) def tnc_disconnect(self): self.transmit_volume_scale.set_sensitive(False) self.mark_toggle_button.set_sensitive(False) self.space_toggle_button.set_sensitive(False) self.ptt_toggle_button.set_sensitive(False) self.ptt_simplex_radiobutton.set_sensitive(False) self.ptt_multiplex_radiobutton.set_sensitive(False) self.dcd_toggle_button.set_sensitive(False) self.kiss_tx_delay_spin_button.set_sensitive(False) self.kiss_persistence_spin_button.set_sensitive(False) self.kiss_slot_time_spin_button.set_sensitive(False) self.kiss_tx_tail_spin_button.set_sensitive(False) self.kiss_duplex_toggle_button.set_sensitive(False) self.conn_track_toggle_button.set_sensitive(False) self.firmware_file_chooser_button.set_sensitive(False) self.upload_button.set_sensitive(False) self.firmware_entry.set_sensitive(False) self.usb_on_button.set_sensitive(False) self.usb_off_button.set_sensitive(False) def tnc_rx_volume(self, value): self.receive_volume_levelbar.set_value(value) self.receive_volume_progressbar.set_fraction(value / 8.0) def tnc_tx_volume(self, value): self.transmit_volume_scale.set_value(value) def tnc_battery_level(self, value): self.battery_level_label.set_text(str(int(value)) + "mV") level = (value - 3400.0) / 100.0 self.battery_level_bar.set_fraction(level / 8.0) def tnc_power_on(self, value): self.usb_on_button.set_sensitive(True) self.usb_on_button.set_active(value) def tnc_power_off(self, value): self.usb_off_button.set_sensitive(True) self.usb_off_button.set_active(value) def tnc_input_atten(self, value): self.input_atten_toggle_button.set_active(value > 0); def tnc_squelch_level(self, value): pass def tnc_tx_delay(self, value): self.kiss_tx_delay_spin_button.set_value(value) def tnc_persistence(self, value): self.kiss_persistence_spin_button.set_value(value) def tnc_slot_time(self, value): self.kiss_slot_time_spin_button.set_value(value) def tnc_tx_tail(self, value): self.kiss_tx_tail_spin_button.set_value(value) def tnc_dcd(self, value): self.dcd_toggle_button.set_sensitive(True) self.dcd_toggle_button.set_active(value == 0) def tnc_verbose(self, value): self.verbose_toggle_button.set_sensitive(True) self.verbose_toggle_button.set_active(value) def tnc_duplex(self, value): self.kiss_duplex_toggle_button.set_sensitive(True) self.kiss_duplex_toggle_button.set_active(value) return if value: self.kiss_duplex_toggle_button.set_image(self.kiss_full_duplex_image) else: self.kiss_duplex_toggle_button.set_image(self.kiss_half_duplex_image) def tnc_conn_track(self, value): self.conn_track_toggle_button.set_sensitive(True) self.conn_track_toggle_button.set_active(value) def tnc_eeprom_save(self): self.eeprom_frame.set_visible(True) self.eeprom_save_button.set_sensitive(True) def tnc_firmware_version(self, value): self.firmware_entry.set_text(value) def tnc_ptt_style(self, value): self.ptt_label.set_visible(True) self.ptt_simplex_radiobutton.set_visible(True) self.ptt_multiplex_radiobutton.set_visible(True) self.ptt_simplex_radiobutton.set_sensitive(True) self.ptt_simplex_radiobutton.set_active(False) self.ptt_multiplex_radiobutton.set_sensitive(True) self.ptt_multiplex_radiobutton.set_active(False) if value == 0: self.ptt_simplex_radiobutton.set_active(True) else: self.ptt_multiplex_radiobutton.set_active(True) def exception(self, e): context = self.status.get_context_id("exception") self.status.pop(context) self.status.push(context, str(e)) # dialog = self.builder.get_object("error_dialog") # dialog.format_secondary_text(str(e)) # dialog.run() # dialog.hide() def notice(self, msg): context = self.status.get_context_id("notice") self.status.pop(context) self.status.push(context, msg) pass def check_firmware_upload_complete(self): assert(self.firmware_gui is not None) if not self.firmware_gui.complete(): self.firmware_gui_tag = GObject.idle_add(self.check_firmware_upload_complete) return self.tnc.upload_firmware_complete() self.firmware_gui.dialog() self.firmware_gui = None
class TncConfigApp(object): def __init__(self): self.tnc = None self.device_path = None self.connect_message = None self.builder = Gtk.Builder() self.builder.add_from_file( os.path.join(glade_location(), "glade/TncConfigApp.glade")) # settings = Gtk.Settings.get_default() # settings.set_property("gtk-font-name", "Cantarell") # settings.set_property("gtk-icon-theme-name", "Oxygen") cssProvider = Gtk.CssProvider() cssProvider.load_from_path(os.path.join(glade_location(), 'glade/TncConfigApp.css')) Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ) self.main_window = self.builder.get_object("main_window") self.main_window.connect("delete-event", self.close) self.stack = self.builder.get_object("config_stack") self.stack.set_sensitive(False) self.sidebar = self.builder.get_object("config_sidebar") self.sidebar.set_sensitive(False) self.init_serial_port_combobox() self.init_audio_input_frame() self.init_audio_output_frame() self.init_power_settings_frame() self.init_kiss_parameters_frame() self.init_modem_settings_frame() self.init_tnc_information_frame() self.init_update_firmware_frame() self.init_save_settings_frame() self.builder.connect_signals(self) self.main_window.show() self.visible_frame=None self.change_visible_frame('audio_input') Notify.init("TncConfigApp") Gtk.main() def __del__(self): Notify.uninit() def close(self, widget, data=None): if self.tnc is not None: self.tnc.disconnect() self.tnc = None Gtk.main_quit() def need_save(self): pass ### Main UI Section def init_serial_port_combobox(self): self.connect_button = self.builder.get_object("connect_button") self.connect_button.set_sensitive(False) self.serial_port_combo_box_text = self.builder.get_object("serial_port_combo_box_text") assert(self.serial_port_combo_box_text is not None) for port in serial.tools.list_ports.comports(): self.serial_port_combo_box_text.append_text(port[0]) def on_connect_button_toggled(self, widget): if widget.get_active(): self.tnc = TncModel(self, self.device_path) self.tnc.connect() elif self.tnc is not None: # Possible race condition here... self.tnc.disconnect() self.tnc = None def on_serial_port_combo_box_changed(self, widget, data = None): self.device_path = widget.get_active_text() self.connect_button.set_sensitive(True) ### GtkStack def on_config_stack_visible_child_name_notify(self, widget, param): # print("visible-child-name", widget.get_visible_child_name()) self.change_visible_frame(widget.get_visible_child_name()) def leave_frame(self, widget_name): """Dynamic dispatch to on_*_leave() function""" getattr(self, "on_" + widget_name + "_leave")() def enter_frame(self, widget_name): """Dynamic dispatch to on_*_enter() function""" getattr(self, "on_" + widget_name + "_enter")() def change_visible_frame(self, name): if self.visible_frame == name: return if self.visible_frame is not None: self.leave_frame(self.visible_frame) self.visible_frame = name self.enter_frame(self.visible_frame) ### Audio Input... def init_audio_input_frame(self): self.audio_input_frame = self.builder.get_object("audio_input_frame") self.audio_input_level_bar = self.builder.get_object("audio_input_level_bar") self.audio_input_level_bar.add_offset_value("audio_input_level_bar-high", 10); self.audio_input_level_bar.add_offset_value("audio_input_level_bar-medium", 8); self.audio_input_level_bar.add_offset_value("audio_input_level_bar-low", 6); self.input_attenuation_box = self.builder.get_object("input_attenuation_box") self.input_attenuation_box.set_visible(False) self.input_attenuation_check_button = self.builder.get_object("input_attenuation_check_button") self.input_gain_box = self.builder.get_object("input_gain_box") self.input_gain_box.set_visible(False) self.input_gain_scale = self.builder.get_object("input_gain_scale") self.input_gain_min_label = self.builder.get_object("input_gain_min_label") self.input_gain_max_label = self.builder.get_object("input_gain_max_label") self.input_twist_box = self.builder.get_object("input_twist_box") self.input_twist_box.set_visible(False) self.input_twist_scale = self.builder.get_object("input_twist_scale") self.input_twist_min_label = self.builder.get_object("input_twist_min_label") self.input_twist_max_label = self.builder.get_object("input_twist_max_label") self.input_auto_adjust_button = self.builder.get_object("input_auto_adjust_button") self.input_auto_adjust_button.set_visible(False) self.last_audio_input_update_time = time.time() def on_audio_input_enter(self): self.last_audio_input_update_time = 0 if self.tnc is not None: self.tnc.stream_audio_on() def on_audio_input_leave(self): # print('on_audio_input_leave') if self.tnc is not None: self.tnc.stream_audio_off() def on_input_attenuation_check_button_toggled(self, widget): self.tnc.set_input_atten(widget.get_active()) self.tnc.stream_audio_on() def on_input_gain_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_input_update_time > 0.1: self.tnc.set_input_gain(int(widget.get_value())) self.last_audio_input_update_time = now def on_input_gain_scale_button_release_event(self, widget, data = None): self.tnc.set_input_gain(int(widget.get_value())) self.last_audio_input_update_time = time.time() def on_input_twist_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_input_update_time > 0.1: self.tnc.set_input_twist(int(widget.get_value())) self.last_audio_input_update_time = now def on_input_twist_scale_button_release_event(self, widget, event, data = None): self.tnc.set_input_twist(int(widget.get_value())) self.last_audio_input_update_time = time.time() def on_input_auto_adjust_button_clicked(self, widget): self.tnc.adjust_input() ### Audio Output... def init_audio_output_frame(self): self.audio_output_frame = self.builder.get_object("audio_output_frame") self.ptt_style_box = self.builder.get_object("ptt_style_box") self.ptt_style_box.set_visible(False) self.ptt_simplex_radio_button = self.builder.get_object("ptt_simplex_radio_button") self.ptt_multiplex_radio_button = self.builder.get_object("ptt_multiplex_radio_button") self.output_gain_scale = self.builder.get_object("output_gain_scale") self.output_twist_box = self.builder.get_object("output_twist_box") self.output_twist_box.set_visible(False) self.output_twist_scale = self.builder.get_object("output_twist_scale") self.mark_tone_radio_button = self.builder.get_object("mark_tone_radio_button") self.space_tone_radio_button = self.builder.get_object("space_tone_radio_button") self.both_tone_radio_button = self.builder.get_object("both_tone_radio_button") self.transmit_toggle_button = self.builder.get_object("transmit_toggle_button") self.last_audio_output_update_time = time.time() def on_audio_output_enter(self): # print('on_audio_output_enter') pass def on_audio_output_leave(self): # print('on_audio_output_leave') pass def on_ptt_simplex_radio_button_toggled(self, widget): if self.tnc is None: return self.tnc.set_ptt_channel(self.ptt_multiplex_radio_button.get_active()) self.need_save() def on_ptt_multiplex_radio_button_toggled(self, widget): """Do not need to check both simplex and multiplex buttons""" pass def on_output_gain_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_output_update_time >= .1: # print('on_output_gain_adjustment_value_changed =', widget.get_value()) self.tnc.set_tx_volume(int(widget.get_value())) self.last_audio_output_update_time = now def on_output_gain_scale_button_release_event(self, widget, data = None): self.tnc.set_tx_volume(int(widget.get_value())) self.last_audio_output_update_time = time.time() def on_output_twist_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_output_update_time >= .1: self.tnc.set_tx_twist(int(widget.get_value())) self.last_audio_output_update_time = now def on_output_twist_scale_button_release_event(self, widget, data = None): self.tnc.set_tx_twist(int(widget.get_value())) self.last_audio_output_update_time = time.time() def on_mark_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(True) self.tnc.set_space(False) def on_space_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(False) self.tnc.set_space(True) def on_both_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(True) self.tnc.set_space(True) def on_transmit_toggle_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(self.mark_tone_radio_button.get_active() or self.both_tone_radio_button.get_active()) self.tnc.set_space(self.space_tone_radio_button.get_active() or self.both_tone_radio_button.get_active()) self.tnc.set_ptt(widget.get_active()) ### Power Settings... def init_power_settings_frame(self): self.power_settings_frame = self.builder.get_object("power_settings_frame") self.power_settings_frame.set_visible(False) self.battery_voltage_label = self.builder.get_object("battery_voltage_label") self.battery_level_bar = self.builder.get_object("battery_level_bar") self.battery_level_bar.add_offset_value("audio_input_level_bar-high", 10); self.battery_level_bar.add_offset_value("audio_input_level_bar-medium", 3); self.battery_level_bar.add_offset_value("audio_input_level_bar-low", 1); self.power_on_check_button = self.builder.get_object("power_on_check_button") self.power_off_check_button = self.builder.get_object("power_off_check_button") def on_power_settings_enter(self): # print('on_power_settings_enter') self.tnc.get_battery_level() def on_power_settings_leave(self): # print('on_power_settings_leave') pass def on_power_on_check_button_toggled(self, widget): self.tnc.set_usb_on(widget.get_active()) def on_power_off_check_button_toggled(self, widget): self.tnc.set_usb_off(widget.get_active()) ### KISS Parameters... def init_kiss_parameters_frame(self): self.kiss_parameters_frame = self.builder.get_object("kiss_parameters_frame") self.tx_delay_spin_button = self.builder.get_object("tx_delay_spin_button") self.slot_time_spin_button = self.builder.get_object("slot_time_spin_button") self.p_persist_spin_button = self.builder.get_object("p_persist_spin_button") self.full_duplex_check_button = self.builder.get_object("full_duplex_check_button") self.last_kiss_parameter_update_time = time.time() def on_kiss_parameters_enter(self): # print('on_kiss_parameters_enter') pass def on_kiss_parameters_leave(self): # print('on_kiss_parameters_leave') pass def on_tx_delay_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_tx_delay(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_tx_delay_spin_button_button_release_event(self, widget): self.tnc.set_tx_delay(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_slot_time_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_time_slot(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_slot_time_spin_button_button_release_event(self, widget): self.tnc.set_time_slot(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_p_persistence_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_persistence(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_p_persist_spin_button_button_release_event(self, widget): self.tnc.set_persistence(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_full_duplex_check_button_toggled(self, widget): self.tnc.set_duplex(widget.get_active()) ### Modem Settings... def init_modem_settings_frame(self): self.modem_settings_frame = self.builder.get_object("modem_settings_frame") self.modem_settings_frame.set_visible(False) self.dcd_check_button = self.builder.get_object("dcd_check_button") self.connection_tracking_check_button = self.builder.get_object("connection_tracking_check_button") self.verbose_output_check_button = self.builder.get_object("verbose_output_check_button") def on_modem_settings_enter(self): # print('on_modem_settings_enter') pass def on_modem_settings_leave(self): # print('on_modem_settings_leave') pass def on_dcd_check_button_toggled(self, widget): self.tnc.set_squelch_level((not widget.get_active()) * 2) def on_connection_tracking_check_button_toggled(self, widget): self.tnc.set_conn_track(widget.get_active()) def on_verbose_output_check_button_toggled(self, widget): self.tnc.set_verbosity(widget.get_active()) ### TNC Information... def init_tnc_information_frame(self): self.tnc_information_frame = self.builder.get_object("tnc_information_frame") self.hardware_version_label = self.builder.get_object("hardware_version_label") self.firmware_version_label = self.builder.get_object("firmware_version_label") self.mac_address_label = self.builder.get_object("mac_address_label") self.serial_number_label = self.builder.get_object("serial_number_label") self.date_time_label = self.builder.get_object("date_time_label") def on_tnc_information_enter(self): # print('on_tnc_information_enter') pass def on_tnc_information_leave(self): # print('on_tnc_information_leave') pass ### Update Firmware... def init_update_firmware_frame(self): self.update_firmware_frame = self.builder.get_object("update_firmware_frame") self.firmware_update_version_label = self.builder.get_object("firmware_update_version_label") self.firmware_file_chooser_button = self.builder.get_object("firmware_file_chooser_button") self.upload_button = self.builder.get_object("upload_button") self.firmware_progress_bar = self.builder.get_object("firmware_progress_bar") # File filter support in Glade is a bit janky. It does not properly # associate the filter to the dialog unless it is done manually as # done below, and there is no way to name the filter in Glade. self.file_filter = self.builder.get_object("tnc1_2_file_filter") self.file_filter.set_name("TNC1 & TNC2 Firmware (*.hex)") self.firmware_file_chooser_button.add_filter(self.file_filter) def on_update_firmware_enter(self): # print('on_update_firmware_enter') pass def on_update_firmware_leave(self): # print('on_update_firmware_leave') pass def on_firmware_file_chooser_button_file_set(self, widget, data=None): self.firmware_file = self.firmware_file_chooser_button.get_filename() self.upload_button.set_sensitive(True) def on_upload_button_clicked(self, widget, data=None): confirm = Gtk.MessageDialog(self.main_window, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, """You are about to upload a firmware image to the TNC. This is irreversible and a potentially damaging operation. Please ensure that the TNC is plugged into USB power and that a valid firmware image for the device has been selected. Are you sure that you wish to proceed?""") confirm.set_title("Confirm Firmware Upload") response = confirm.run() confirm.destroy() if response == Gtk.ResponseType.CANCEL: return self.firmware_upload_complete = None self.firmware_gui_tag = GLib.idle_add(self.check_firmware_upload_complete) self.sidebar.set_sensitive(False) # print("firmware file =", self.firmware_file) self.tnc.upload_firmware(self.firmware_file, self) ### Save Settings... def init_save_settings_frame(self): self.save_settings_frame = self.builder.get_object("save_settings_frame") self.save_settings_frame.set_visible(False) self.save_settings_button = self.builder.get_object("save_settings_button") def on_save_settings_enter(self): # print('on_save_settings_enter') pass def on_save_settings_leave(self): # print('on_save_settings_leave') pass def on_save_settings_button_clicked(self, widget): self.tnc.save_eeprom_settings() ### TNC events def tnc_connect(self): self.stack.set_visible_child_name('audio_input') self.stack.set_sensitive(True) self.sidebar.set_sensitive(True) self.serial_port_combo_box_text.set_sensitive(False) self.connect_button.set_label("gtk-disconnect") self.firmware_progress_bar.set_text("Select firmware image...") def tnc_disconnect(self): self.stack.set_visible_child_name('audio_input') self.stack.set_sensitive(False) self.sidebar.set_sensitive(False) self.serial_port_combo_box_text.set_sensitive(True) self.connect_button.set_label("gtk-connect") self.connect_button.set_active(False) self.tnc = None ### Audio Input def tnc_rx_volume(self, value): self.audio_input_level_bar.set_value(value * 1.25) def tnc_input_atten(self, value): self.input_attenuation_box.set_visible(True) self.input_attenuation_check_button.set_active(value > 0); def tnc_input_gain(self, value): self.input_gain_box.set_visible(True) self.input_gain_scale.set_value(value); def tnc_input_twist(self, value): self.input_twist_box.set_visible(True) self.input_twist_scale.set_value(value); def tnc_min_input_twist(self, value): self.input_twist_min_label.set_text("{}dB".format(value)) def tnc_max_input_twist(self, value): self.input_twist_max_label.set_text("{}dB".format(value)) def tnc_min_input_gain(self, value): self.input_gain_min_label.set_text("{}".format(value)) def tnc_max_input_gain(self, value): self.input_gain_max_label.set_text("{}".format(value)) def tnc_adjust_input(self): self.input_auto_adjust_button.set_visible(True) self.input_auto_adjust_button.set_sensitive(True) ### Audio Output def tnc_ptt_style(self, value): self.ptt_style_box.set_visible(True) if value == 0: self.ptt_simplex_radio_button.set_active(True) else: self.ptt_multiplex_radio_button.set_active(True) def tnc_tx_volume(self, gain): self.output_gain_scale.set_value(gain) def tnc_tx_twist(self, gain): self.output_twist_box.set_visible(True) self.output_twist_scale.set_value(gain) ### Power Settings def tnc_battery_level(self, value): self.power_settings_frame.set_visible(True) self.battery_voltage_label.set_text(str(int(value)) + "mV") level_bar_value = min(max(0, value - 3300) / 90.0, 10.0) self.battery_level_bar.set_value(level_bar_value) def tnc_power_on(self, value): self.power_settings_frame.set_visible(True) self.power_on_check_button.set_sensitive(True) self.power_on_check_button.set_active(value) def tnc_power_off(self, value): self.power_settings_frame.set_visible(True) self.power_off_check_button.set_sensitive(True) self.power_off_check_button.set_active(value) ### KISS Parameters def tnc_tx_delay(self, value): self.tx_delay_spin_button.set_value(value) def tnc_slot_time(self, value): self.slot_time_spin_button.set_value(value) def tnc_persistence(self, value): self.p_persist_spin_button.set_value(value) def tnc_tx_tail(self, value): # No longer used or settable pass def tnc_duplex(self, value): self.full_duplex_check_button.set_sensitive(True) self.full_duplex_check_button.set_active(value) ### Modem Settings def tnc_dcd(self, value): self.modem_settings_frame.set_visible(True) self.dcd_check_button.set_sensitive(True) self.dcd_check_button.set_active(value == 0) def tnc_conn_track(self, value): self.modem_settings_frame.set_visible(True) self.connection_tracking_check_button.set_sensitive(True) self.connection_tracking_check_button.set_active(value) def tnc_verbose(self, value): self.modem_settings_frame.set_visible(True) self.verbose_output_check_button.set_sensitive(True) self.verbose_output_check_button.set_active(value) ### TNC Information def tnc_hardware_version(self, value): self.hardware_version_label.set_text(value) def tnc_firmware_version(self, value): self.firmware_version_label.set_text(value) self.firmware_update_version_label.set_text(value) def tnc_mac_address(self, value): self.mac_address_label.set_text(value) def tnc_serial_number(self, value): self.serial_number_label.set_text(value) def tnc_date_time(self, value): self.date_time_label.set_text(value) ### Update Firmware def tnc_dfu_firmware(self): self.update_firmware_frame.set_visible(False) ### Save Settings def tnc_eeprom_save(self): self.save_settings_frame.set_visible(True) self.save_settings_button.set_sensitive(True) def do_exception_dialog(self, ex): confirm = Gtk.MessageDialog(parent = self.main_window, flags = 0, message_type = Gtk.MessageType.ERROR, buttons = Gtk.ButtonsType.OK, text = str(ex)) confirm.set_title("Error") confirm.run() confirm.destroy() def exception(self, ex): # print(str(ex)) GLib.idle_add(self.do_exception_dialog, ex) ### Firmware Update Callbacks def is_firmware_update_complete(self): return self.firmware_upload_complete is not None def firmware_set_steps(self, steps): self.progress_bar_step = 1.0 / steps # print("progress bar step: {}".format(self.progress_bar_step)) GLib.idle_add(self.firmware_progress_bar.set_pulse_step, self.progress_bar_step) def firmware_writing(self): self.progress_bar_progress = 0.0 GLib.idle_add(self.firmware_progress_bar.set_text, "Writing...") GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_verifying(self): self.progress_bar_progress = 0.0 GLib.idle_add(self.firmware_progress_bar.set_text, "Verifying...") GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_pulse(self): self.progress_bar_progress += self.progress_bar_step # Pulse doesn't work for some unknown reason # GLib.idle_add(self.firmware_progress_bar.pulse) GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_success(self): self.firmware_upload_complete = True # self.firmware_progress_bar.set_text("Firmware upload complete") # self.sidebar.set_sensitive(True) # self.tnc.disconnect() def firmware_failure(self, msg): self.firmware_upload_complete = False self.firmware_upload_msg = msg # self.firmware_progress_bar.set_text("Firmware upload failed") # self.sidebar.set_sensitive(True) def check_firmware_upload_complete(self): if not self.is_firmware_update_complete(): self.firmware_gui_tag = GLib.timeout_add(1, self.check_firmware_upload_complete) return if self.firmware_upload_complete: self.firmware_progress_bar.set_text("Firmware upload complete") Notify.Notification.new("Firmware upload complete").show() # self.tnc.disconnect() else: self.firmware_progress_bar.set_text("Firmware upload failed") Notify.Notification.new("Firmware upload failed: {}".format(self.firmware_upload_msg)).show() self.tnc.upload_firmware_complete() self.sidebar.set_sensitive(True)
class MobilinkdTnc1Config(object): def __init__(self): self.tnc = None self.connect_message = None self.builder = Gtk.Builder() self.builder.add_from_file( os.path.join(glade_location(), "glade/MobilinkdTnc1Config.glade")) self.window = self.builder.get_object("window") self.window.connect("delete-event", self.close) self.init_serial_port_combobox() self.init_power_section() self.init_transmit_volume() self.init_receive_volume() self.init_kiss_parameters() self.init_firmware_section() self.init_eeprom_section() self.status = self.builder.get_object("statusbar") self.builder.connect_signals(self) self.tnc_disconnect() self.window.show() Gtk.main() def close(self, widget, data=None): if self.tnc is not None: self.tnc.disconnect() self.tnc = None Gtk.main_quit() def init_serial_port_combobox(self): self.serial_port_combobox = self.builder.get_object( "serial_port_combobox") for port in comports(): self.serial_port_combobox.append_text(port[0]) def on_serial_port_combobox_changed(self, widget, data=None): text = widget.get_active_text() if text != None: self.tnc = TncModel(self, text) def init_power_section(self): self.battery_level_label = self.builder.get_object( "battery_level_label") self.battery_level_bar = self.builder.get_object("battery_level_bar") self.battery_level_bar.set_fraction(0.0) self.power_control_box = self.builder.get_object("power_control_box") self.usb_on_button = self.builder.get_object("usb_on_button") self.usb_off_button = self.builder.get_object("usb_off_button") self.usb_on_button.set_sensitive(False) self.usb_off_button.set_sensitive(False) def init_eeprom_section(self): self.eeprom_frame = self.builder.get_object("eeprom_frame") self.eeprom_save_button = self.builder.get_object("eeprom_save_button") self.eeprom_save_button.set_sensitive(False) self.eeprom_frame.set_visible(False) def init_transmit_volume(self): self.transmit_volume_scale = self.builder.get_object( "transmit_volume_scale") self.transmit_volume_scale.set_range(16.0, 255.0) self.transmit_volume_scale.set_value(128.0) self.transmit_volume_scale.set_sensitive(False) self.mark_toggle_button = self.builder.get_object("mark_toggle_button") self.space_toggle_button = self.builder.get_object( "space_toggle_button") self.ptt_toggle_button = self.builder.get_object("ptt_toggle_button") def on_mark_toggle_button_toggled(self, widget, data=None): self.tnc.set_mark(widget.get_active()) def on_space_toggle_button_toggled(self, widget, data=None): self.tnc.set_space(widget.get_active()) def on_ptt_toggle_button_toggled(self, widget, data=None): self.tnc.set_ptt(widget.get_active()) def on_input_atten_toggle_button_toggled(self, widget, data=None): self.tnc.set_input_atten(widget.get_active()) def on_transmit_volume_scale_change_value(self, widget, scroll, value, data=None): if value > 255: value = 255 if value < 0: value = 0 widget.set_value(int(value)) self.tnc.set_tx_volume(int(value)) return True def init_receive_volume(self): self.receive_volume_levelbar = self.builder.get_object( "receive_volume_levelbar") self.receive_volume_levelbar.add_offset_value(Gtk.LEVEL_BAR_OFFSET_LOW, 5.0) self.receive_volume_levelbar.add_offset_value( Gtk.LEVEL_BAR_OFFSET_HIGH, 7.0) self.receive_volume_levelbar.set_value(0.0) self.input_atten_toggle_button = self.builder.get_object( "input_atten_toggle_button") self.receive_volume_progressbar = self.builder.get_object( "receive_volume_progressbar") if os.name != "posix": self.receive_volume_progressbar.show() self.receive_volume_levelbar.hide() self.receive_volume_progressbar.set_fraction(0.0) def init_kiss_parameters(self): self.dcd_toggle_button = self.builder.get_object("dcd_toggle_button") self.kiss_tx_delay_spin_button = self.builder.get_object( "kiss_tx_delay_spin_button") self.kiss_tx_delay_spin_button.set_range(0.0, 255.0) self.kiss_tx_delay_spin_button.set_increments(1.0, 10.0) self.kiss_tx_delay_spin_button.set_value(50) self.kiss_persistence_spin_button = self.builder.get_object( "kiss_persistence_spin_button") self.kiss_persistence_spin_button.set_range(0.0, 255.0) self.kiss_persistence_spin_button.set_increments(1.0, 10.0) self.kiss_persistence_spin_button.set_value(63) self.kiss_slot_time_spin_button = self.builder.get_object( "kiss_slot_time_spin_button") self.kiss_slot_time_spin_button.set_range(0.0, 255.0) self.kiss_slot_time_spin_button.set_increments(1.0, 10.0) self.kiss_slot_time_spin_button.set_value(25) self.kiss_tx_tail_spin_button = self.builder.get_object( "kiss_tx_tail_spin_button") self.kiss_tx_tail_spin_button.set_range(0.0, 255.0) self.kiss_tx_tail_spin_button.set_increments(1.0, 10.0) self.kiss_tx_tail_spin_button.set_value(2) self.kiss_duplex_toggle_button = self.builder.get_object( "kiss_duplex_toggle_button") self.kiss_full_duplex_image = self.builder.get_object( "kiss_full_duplex_image") self.kiss_half_duplex_image = self.builder.get_object( "kiss_half_duplex_image") self.conn_track_toggle_button = self.builder.get_object( "conn_track_toggle_button") self.verbose_toggle_button = self.builder.get_object( "verbose_toggle_button") self.ptt_label = self.builder.get_object("ptt_label") self.ptt_simplex_radiobutton = self.builder.get_object( "ptt_simplex_radiobutton") self.ptt_multiplex_radiobutton = self.builder.get_object( "ptt_multiplex_radiobutton") def on_dcd_toggled(self, widget, data=None): self.tnc.set_squelch_level((not widget.get_active()) * 2) def on_ptt_toggled(self, widget, data=None): if widget.get_active(): self.tnc.set_ptt_channel( self.ptt_multiplex_radiobutton.get_active()) def on_verbose_toggled(self, widget, data=None): self.tnc.set_verbosity(widget.get_active()) def on_kiss_duplex_toggled(self, widget, data=None): self.tnc.set_duplex(widget.get_active()) def on_conn_track_toggled(self, widget, data=None): self.tnc.set_conn_track(widget.get_active()) def on_kiss_tx_delay_spin_button_value_changed(self, widget, data=None): self.tnc.set_tx_delay(widget.get_value_as_int()) def on_kiss_persistence_spin_button_value_changed(self, widget, data=None): self.tnc.set_persistence(widget.get_value_as_int()) def on_kiss_slot_time_spin_button_value_changed(self, widget, data=None): self.tnc.set_time_slot(widget.get_value_as_int()) def on_kiss_tx_tail_spin_button_value_changed(self, widget, data=None): self.tnc.set_tx_tail(widget.get_value_as_int()) def on_connect_button_clicked(self, widget, data=None): if self.tnc is None: self.connect_message = self.status.push( 1, "Please choose a serial port.") return if self.tnc.connected(): self.connect_message = self.status.push(1, "Already connected.") return if self.connect_message is not None: self.status.remove(1, self.connect_message) self.tnc.connect() def on_window_destroy(self, widget, data=None): print "quitting" Gtk.main_quit() def init_firmware_section(self): self.firmware_file_chooser_button = self.builder.get_object( "firmware_file_chooser_button") self.upload_button = self.builder.get_object("upload_button") self.firmware_entry = self.builder.get_object("firmware_entry") def on_firmware_file_chooser_button_file_set(self, widget, data=None): self.firmware_file = self.firmware_file_chooser_button.get_filename() self.upload_button.set_sensitive(True) def on_eeprom_save_button_clicked(self, widget, data=None): self.tnc.save_eeprom_settings() def on_usb_on_button_toggled(self, widget, data=None): self.tnc.set_usb_on(widget.get_active()) def on_usb_off_button_toggled(self, widget, data=None): self.tnc.set_usb_off(widget.get_active()) def on_upload_button_clicked(self, widget, data=None): self.firmware_gui = FirmwareUploadGui(self.builder, self.tnc) self.tnc.upload_firmware(self.firmware_file, self.firmware_gui) self.firmware_gui_tag = GObject.idle_add( self.check_firmware_upload_complete) def tnc_connect(self): self.serial_port_combobox.set_sensitive(False) self.transmit_volume_scale.set_sensitive(True) self.mark_toggle_button.set_sensitive(True) self.mark_toggle_button.set_active(False) self.space_toggle_button.set_sensitive(True) self.space_toggle_button.set_active(False) self.ptt_toggle_button.set_sensitive(True) self.ptt_toggle_button.set_active(False) self.dcd_toggle_button.set_sensitive(False) self.dcd_toggle_button.set_active(False) self.verbose_toggle_button.set_sensitive(False) self.verbose_toggle_button.set_active(False) self.kiss_tx_delay_spin_button.set_sensitive(True) self.kiss_persistence_spin_button.set_sensitive(True) self.kiss_slot_time_spin_button.set_sensitive(True) self.kiss_tx_tail_spin_button.set_sensitive(True) self.kiss_duplex_toggle_button.set_sensitive(False) self.kiss_duplex_toggle_button.set_active(False) self.conn_track_toggle_button.set_sensitive(False) self.conn_track_toggle_button.set_active(False) self.firmware_file_chooser_button.set_sensitive(True) self.upload_button.set_sensitive(False) self.firmware_entry.set_sensitive(True) def tnc_disconnect(self): self.transmit_volume_scale.set_sensitive(False) self.mark_toggle_button.set_sensitive(False) self.space_toggle_button.set_sensitive(False) self.ptt_toggle_button.set_sensitive(False) self.ptt_simplex_radiobutton.set_sensitive(False) self.ptt_multiplex_radiobutton.set_sensitive(False) self.dcd_toggle_button.set_sensitive(False) self.kiss_tx_delay_spin_button.set_sensitive(False) self.kiss_persistence_spin_button.set_sensitive(False) self.kiss_slot_time_spin_button.set_sensitive(False) self.kiss_tx_tail_spin_button.set_sensitive(False) self.kiss_duplex_toggle_button.set_sensitive(False) self.conn_track_toggle_button.set_sensitive(False) self.firmware_file_chooser_button.set_sensitive(False) self.upload_button.set_sensitive(False) self.firmware_entry.set_sensitive(False) self.usb_on_button.set_sensitive(False) self.usb_off_button.set_sensitive(False) def tnc_rx_volume(self, value): self.receive_volume_levelbar.set_value(value) self.receive_volume_progressbar.set_fraction(value / 8.0) def tnc_tx_volume(self, value): self.transmit_volume_scale.set_value(value) def tnc_battery_level(self, value): self.battery_level_label.set_text(str(int(value)) + "mV") level = (value - 3400.0) / 100.0 self.battery_level_bar.set_fraction(level / 8.0) def tnc_power_on(self, value): self.usb_on_button.set_sensitive(True) self.usb_on_button.set_active(value) def tnc_power_off(self, value): self.usb_off_button.set_sensitive(True) self.usb_off_button.set_active(value) def tnc_input_atten(self, value): self.input_atten_toggle_button.set_active(value > 0) def tnc_squelch_level(self, value): pass def tnc_tx_delay(self, value): self.kiss_tx_delay_spin_button.set_value(value) def tnc_persistence(self, value): self.kiss_persistence_spin_button.set_value(value) def tnc_slot_time(self, value): self.kiss_slot_time_spin_button.set_value(value) def tnc_tx_tail(self, value): self.kiss_tx_tail_spin_button.set_value(value) def tnc_dcd(self, value): self.dcd_toggle_button.set_sensitive(True) self.dcd_toggle_button.set_active(value == 0) def tnc_verbose(self, value): self.verbose_toggle_button.set_sensitive(True) self.verbose_toggle_button.set_active(value) def tnc_duplex(self, value): self.kiss_duplex_toggle_button.set_sensitive(True) self.kiss_duplex_toggle_button.set_active(value) return if value: self.kiss_duplex_toggle_button.set_image( self.kiss_full_duplex_image) else: self.kiss_duplex_toggle_button.set_image( self.kiss_half_duplex_image) def tnc_conn_track(self, value): self.conn_track_toggle_button.set_sensitive(True) self.conn_track_toggle_button.set_active(value) def tnc_eeprom_save(self): self.eeprom_frame.set_visible(True) self.eeprom_save_button.set_sensitive(True) def tnc_firmware_version(self, value): self.firmware_entry.set_text(value) def tnc_ptt_style(self, value): self.ptt_label.set_visible(True) self.ptt_simplex_radiobutton.set_visible(True) self.ptt_multiplex_radiobutton.set_visible(True) self.ptt_simplex_radiobutton.set_sensitive(True) self.ptt_simplex_radiobutton.set_active(False) self.ptt_multiplex_radiobutton.set_sensitive(True) self.ptt_multiplex_radiobutton.set_active(False) if value == 0: self.ptt_simplex_radiobutton.set_active(True) else: self.ptt_multiplex_radiobutton.set_active(True) def exception(self, e): context = self.status.get_context_id("exception") self.status.pop(context) self.status.push(context, str(e)) # dialog = self.builder.get_object("error_dialog") # dialog.format_secondary_text(str(e)) # dialog.run() # dialog.hide() def notice(self, msg): context = self.status.get_context_id("notice") self.status.pop(context) self.status.push(context, msg) pass def check_firmware_upload_complete(self): assert (self.firmware_gui is not None) if not self.firmware_gui.complete(): self.firmware_gui_tag = GObject.idle_add( self.check_firmware_upload_complete) return self.tnc.upload_firmware_complete() self.firmware_gui.dialog() self.firmware_gui = None
class TncConfigApp(object): def __init__(self, device_path=None): self.tnc = None self.device_path = None self.connect_message = None self.builder = Gtk.Builder() self.builder.add_from_file( os.path.join(glade_location(), "glade/TncConfigApp.glade")) # settings = Gtk.Settings.get_default() # settings.set_property("gtk-font-name", "Cantarell") # settings.set_property("gtk-icon-theme-name", "Oxygen") # The version of GTK+ available to us on Windows is rather old and requires # a different CSS file. cssProvider = Gtk.CssProvider() if os.name == 'nt': cssProvider.load_from_path( os.path.join(glade_location(), 'glade/TncConfigApp-win.css')) else: cssProvider.load_from_path( os.path.join(glade_location(), 'glade/TncConfigApp.css')) Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) self.main_window = self.builder.get_object("main_window") self.main_window.connect("delete-event", self.close) self.stack = self.builder.get_object("config_stack") self.stack.set_sensitive(False) self.sidebar = self.builder.get_object("config_sidebar") self.sidebar.set_sensitive(False) self.modem_types = { 1: "1200 baud AFSK", 2: "300 baud AFSK", 3: "9600 baud G3RUH/GFSK", 5: "M17 4-FSK" } self.supported_modem_types = {} self.init_audio_input_frame() self.init_audio_output_frame() self.init_power_settings_frame() self.init_kiss_parameters_frame() self.init_modem_settings_frame() self.init_tnc_information_frame() self.init_update_firmware_frame() self.init_save_settings_frame() self.init_about_frame() self.builder.connect_signals(self) self.init_serial_port_combobox() self.main_window.show() self.visible_frame = None self.change_visible_frame('about') self.stack.set_visible_child_name('about') Notify.init("TncConfigApp") Gtk.main() def __del__(self): Notify.uninit() def close(self, widget, data=None): if self.tnc is not None: self.tnc.disconnect() self.tnc = None Gtk.main_quit() def get_modem_number(self, modem_name): for number, name in self.modem_types.items(): if name == modem_name: return number else: return None def need_save(self): pass ### Main UI Section def init_serial_port_combobox(self): self.connect_button = self.builder.get_object("connect_button") self.connect_button.set_sensitive(False) self.serial_port_combo_box_text = self.builder.get_object( "serial_port_combo_box_text") assert (self.serial_port_combo_box_text is not None) for port in serial.tools.list_ports.comports(): self.serial_port_combo_box_text.append_text(port[0]) def on_connect_button_toggled(self, widget): if widget.get_active(): self.tnc = TncModel(self, self.device_path) self.tnc.connect() elif self.tnc is not None: # Possible race condition here... self.tnc.disconnect() self.tnc = None def on_serial_port_combo_box_changed(self, widget, data=None): self.device_path = widget.get_active_text() self.connect_button.set_sensitive(True) ### GtkStack def on_config_stack_visible_child_name_notify(self, widget, param): # print("visible-child-name", widget.get_visible_child_name()) self.change_visible_frame(widget.get_visible_child_name()) def leave_frame(self, widget_name): """Dynamic dispatch to on_*_leave() function""" getattr(self, "on_" + widget_name + "_leave")() def enter_frame(self, widget_name): """Dynamic dispatch to on_*_enter() function""" getattr(self, "on_" + widget_name + "_enter")() def change_visible_frame(self, name): if self.visible_frame == name: return if self.visible_frame is not None: self.leave_frame(self.visible_frame) self.visible_frame = name self.enter_frame(self.visible_frame) ### Audio Input... def init_audio_input_frame(self): self.audio_input_frame = self.builder.get_object("audio_input_frame") self.audio_input_level_bar = self.builder.get_object( "audio_input_level_bar") self.audio_input_level_bar.add_offset_value( "audio_input_level_bar-high", 10) self.audio_input_level_bar.add_offset_value( "audio_input_level_bar-medium", 8) self.audio_input_level_bar.add_offset_value( "audio_input_level_bar-low", 6) self.input_attenuation_box = self.builder.get_object( "input_attenuation_box") self.input_attenuation_box.set_visible(False) self.input_attenuation_check_button = self.builder.get_object( "input_attenuation_check_button") self.input_gain_box = self.builder.get_object("input_gain_box") self.input_gain_box.set_visible(False) self.input_gain_scale = self.builder.get_object("input_gain_scale") self.input_gain_min_label = self.builder.get_object( "input_gain_min_label") self.input_gain_max_label = self.builder.get_object( "input_gain_max_label") self.input_twist_box = self.builder.get_object("input_twist_box") self.input_twist_box.set_visible(False) self.input_twist_scale = self.builder.get_object("input_twist_scale") self.input_twist_min_label = self.builder.get_object( "input_twist_min_label") self.input_twist_max_label = self.builder.get_object( "input_twist_max_label") self.input_auto_adjust_button = self.builder.get_object( "input_auto_adjust_button") self.input_auto_adjust_button.set_visible(False) self.last_audio_input_update_time = time.time() def on_audio_input_enter(self): self.last_audio_input_update_time = 0 if self.tnc is not None and self.connect_button.get_active(): self.tnc.stream_audio_on() def on_audio_input_leave(self): # print('on_audio_input_leave') if self.tnc is not None: self.tnc.stream_audio_off() def on_input_attenuation_check_button_toggled(self, widget): self.tnc.set_input_atten(widget.get_active()) self.tnc.stream_audio_on() def on_input_gain_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_input_update_time > 0.1: self.tnc.set_input_gain(int(widget.get_value())) self.last_audio_input_update_time = now def on_input_gain_scale_button_release_event(self, widget, data=None): self.tnc.set_input_gain(int(widget.get_value())) self.last_audio_input_update_time = time.time() def on_input_twist_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_input_update_time > 0.1: self.tnc.set_input_twist(int(widget.get_value())) self.last_audio_input_update_time = now def on_input_twist_scale_button_release_event(self, widget, event, data=None): self.tnc.set_input_twist(int(widget.get_value())) self.last_audio_input_update_time = time.time() def on_input_auto_adjust_button_clicked(self, widget): self.tnc.adjust_input() ### Audio Output... def init_audio_output_frame(self): self.audio_output_frame = self.builder.get_object("audio_output_frame") self.ptt_style_box = self.builder.get_object("ptt_style_box") self.ptt_style_box.set_visible(False) self.ptt_simplex_radio_button = self.builder.get_object( "ptt_simplex_radio_button") self.ptt_multiplex_radio_button = self.builder.get_object( "ptt_multiplex_radio_button") self.output_gain_scale = self.builder.get_object("output_gain_scale") self.output_twist_box = self.builder.get_object("output_twist_box") self.output_twist_box.set_visible(False) self.output_twist_scale = self.builder.get_object("output_twist_scale") self.mark_tone_radio_button = self.builder.get_object( "mark_tone_radio_button") self.space_tone_radio_button = self.builder.get_object( "space_tone_radio_button") self.both_tone_radio_button = self.builder.get_object( "both_tone_radio_button") self.transmit_toggle_button = self.builder.get_object( "transmit_toggle_button") self.last_audio_output_update_time = time.time() def on_audio_output_enter(self): # print('on_audio_output_enter') pass def on_audio_output_leave(self): # print('on_audio_output_leave') pass def on_ptt_simplex_radio_button_toggled(self, widget): if self.tnc is None: return self.tnc.set_ptt_channel(self.ptt_multiplex_radio_button.get_active()) self.need_save() def on_ptt_multiplex_radio_button_toggled(self, widget): """Do not need to check both simplex and multiplex buttons""" pass def on_output_gain_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_output_update_time >= .1: # print('on_output_gain_adjustment_value_changed =', widget.get_value()) self.tnc.set_tx_volume(int(widget.get_value())) self.last_audio_output_update_time = now def on_output_gain_scale_button_release_event(self, widget, data=None): self.tnc.set_tx_volume(int(widget.get_value())) self.last_audio_output_update_time = time.time() def on_output_twist_adjustment_value_changed(self, widget): now = time.time() if now - self.last_audio_output_update_time >= .1: self.tnc.set_tx_twist(int(widget.get_value())) self.last_audio_output_update_time = now def on_output_twist_scale_button_release_event(self, widget, data=None): self.tnc.set_tx_twist(int(widget.get_value())) self.last_audio_output_update_time = time.time() def on_mark_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(True) self.tnc.set_space(False) def on_space_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(False) self.tnc.set_space(True) def on_both_tone_radio_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(True) self.tnc.set_space(True) def on_transmit_toggle_button_toggled(self, widget): if widget.get_active(): self.tnc.set_mark(self.mark_tone_radio_button.get_active() or self.both_tone_radio_button.get_active()) self.tnc.set_space(self.space_tone_radio_button.get_active() or self.both_tone_radio_button.get_active()) self.tnc.set_ptt(widget.get_active()) ### Power Settings... def init_power_settings_frame(self): self.power_settings_frame = self.builder.get_object( "power_settings_frame") self.power_settings_frame.set_visible(False) self.battery_voltage_label = self.builder.get_object( "battery_voltage_label") self.battery_level_bar = self.builder.get_object("battery_level_bar") self.battery_level_bar.add_offset_value("audio_input_level_bar-high", 10) self.battery_level_bar.add_offset_value("audio_input_level_bar-medium", 3) self.battery_level_bar.add_offset_value("audio_input_level_bar-low", 1) self.power_on_check_button = self.builder.get_object( "power_on_check_button") self.power_off_check_button = self.builder.get_object( "power_off_check_button") def on_power_settings_enter(self): # print('on_power_settings_enter') self.tnc.get_battery_level() def on_power_settings_leave(self): # print('on_power_settings_leave') pass def on_power_on_check_button_toggled(self, widget): self.tnc.set_usb_on(widget.get_active()) def on_power_off_check_button_toggled(self, widget): self.tnc.set_usb_off(widget.get_active()) ### KISS Parameters... def init_kiss_parameters_frame(self): self.kiss_parameters_frame = self.builder.get_object( "kiss_parameters_frame") self.tx_delay_spin_button = self.builder.get_object( "tx_delay_spin_button") self.slot_time_spin_button = self.builder.get_object( "slot_time_spin_button") self.p_persist_spin_button = self.builder.get_object( "p_persist_spin_button") self.full_duplex_check_button = self.builder.get_object( "full_duplex_check_button") self.last_kiss_parameter_update_time = time.time() def on_kiss_parameters_enter(self): # print('on_kiss_parameters_enter') pass def on_kiss_parameters_leave(self): # print('on_kiss_parameters_leave') pass def on_tx_delay_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_tx_delay(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_tx_delay_spin_button_button_release_event(self, widget, event): self.tnc.set_tx_delay(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_slot_time_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_time_slot(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_slot_time_spin_button_button_release_event(self, widget, event): self.tnc.set_time_slot(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_p_persistence_adjustment_value_changed(self, widget): now = time.time() if now - self.last_kiss_parameter_update_time >= .1: self.tnc.set_persistence(int(widget.get_value())) self.last_kiss_parameter_update_time = now def on_p_persist_spin_button_button_release_event(self, widget, event): self.tnc.set_persistence(int(widget.get_value())) self.last_kiss_parameter_update_time = time.time() def on_full_duplex_check_button_toggled(self, widget): self.tnc.set_duplex(widget.get_active()) ### Modem Settings... def init_modem_settings_frame(self): self.modem_settings_frame = self.builder.get_object( "modem_settings_frame") self.modem_settings_frame.set_visible(False) self.dcd_check_button = self.builder.get_object("dcd_check_button") self.connection_tracking_check_button = self.builder.get_object( "connection_tracking_check_button") self.verbose_output_check_button = self.builder.get_object( "verbose_output_check_button") self.passall_check_button = self.builder.get_object( "passall_check_button") self.modem_type_combo_box_text = self.builder.get_object( "modem_type_combo_box_text") self.rx_reverse_polarity_check_button = self.builder.get_object( "rx_reverse_polarity_check_button") self.tx_reverse_polarity_check_button = self.builder.get_object( "tx_reverse_polarity_check_button") self.modem_settings_active = False def on_modem_settings_enter(self): # print('on_modem_settings_enter') self.modem_settings_active = True def on_modem_settings_leave(self): # print('on_modem_settings_leave') self.modem_settings_active = False def on_dcd_check_button_toggled(self, widget): self.tnc.set_squelch_level((not widget.get_active()) * 2) def on_connection_tracking_check_button_toggled(self, widget): self.tnc.set_conn_track(widget.get_active()) def on_verbose_output_check_button_toggled(self, widget): self.tnc.set_verbosity(widget.get_active()) def on_passall_check_button_toggled(self, widget): self.tnc.set_passall(widget.get_active()) def on_rx_reverse_polarity_check_button_toggled(self, widget): if self.tx_reverse_polarity_check_button.get_visible(): self.tnc.set_rx_reverse_polarity(widget.get_active()) def on_tx_reverse_polarity_check_button_toggled(self, widget): if self.rx_reverse_polarity_check_button.get_visible(): self.tnc.set_tx_reverse_polarity(widget.get_active()) def on_modem_type_combo_box_text_changed(self, widget): modem_number = self.get_modem_number(widget.get_active_text()) if modem_number is None: return if self.modem_settings_active: # User interaction. self.tnc.set_modem_type(modem_number) ### TNC Information... def init_tnc_information_frame(self): self.tnc_information_frame = self.builder.get_object( "tnc_information_frame") self.hardware_version_label = self.builder.get_object( "hardware_version_label") self.firmware_version_label = self.builder.get_object( "firmware_version_label") self.mac_address_label = self.builder.get_object("mac_address_label") self.serial_number_label = self.builder.get_object( "serial_number_label") self.date_time_label = self.builder.get_object("date_time_label") def on_tnc_information_enter(self): # print('on_tnc_information_enter') pass def on_tnc_information_leave(self): # print('on_tnc_information_leave') pass ### Update Firmware... def init_update_firmware_frame(self): self.update_firmware_frame = self.builder.get_object( "update_firmware_frame") self.firmware_update_version_label = self.builder.get_object( "firmware_update_version_label") self.firmware_file_chooser_button = self.builder.get_object( "firmware_file_chooser_button") self.upload_button = self.builder.get_object("upload_button") self.firmware_progress_bar = self.builder.get_object( "firmware_progress_bar") # File filter support in Glade is a bit janky. It does not properly # associate the filter to the dialog unless it is done manually as # done below, and there is no way to name the filter in Glade. self.file_filter = self.builder.get_object("tnc1_2_file_filter") self.file_filter.set_name("TNC1 & TNC2 Firmware (*.hex)") self.firmware_file_chooser_button.add_filter(self.file_filter) def on_update_firmware_enter(self): # print('on_update_firmware_enter') pass def on_update_firmware_leave(self): # print('on_update_firmware_leave') pass def on_firmware_file_chooser_button_file_set(self, widget, data=None): self.firmware_file = self.firmware_file_chooser_button.get_filename() self.upload_button.set_sensitive(True) def on_upload_button_clicked(self, widget, data=None): confirm = Gtk.MessageDialog( parent=self.main_window, flags=0, message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK_CANCEL, text="".join([ 'You are about to upload a firmware image to the TNC. ', 'This is irreversible and a potentially damaging operation. ', 'Please ensure that the TNC is plugged into USB power and ', 'that a valid firmware image for the device has been selected.', '\n\nAre you sure that you wish to proceed?' ])) confirm.set_title("Confirm Firmware Upload") response = confirm.run() confirm.destroy() if response == Gtk.ResponseType.CANCEL: return self.firmware_upload_complete = None self.firmware_gui_tag = GLib.idle_add( self.check_firmware_upload_complete) self.sidebar.set_sensitive(False) # print("firmware file =", self.firmware_file) self.tnc.upload_firmware(self.firmware_file, self) ### Save Settings... def init_save_settings_frame(self): self.save_settings_frame = self.builder.get_object( "save_settings_frame") self.save_settings_frame.set_visible(False) self.save_settings_button = self.builder.get_object( "save_settings_button") def on_save_settings_enter(self): # print('on_save_settings_enter') pass def on_save_settings_leave(self): # print('on_save_settings_leave') pass def on_save_settings_button_clicked(self, widget): self.tnc.save_eeprom_settings() def init_about_frame(self): self.about_frame = self.builder.get_object("about_frame") self.about_frame.set_visible(True) def on_about_enter(self): # print('on_save_settings_leave') pass def on_about_leave(self): # print('on_save_settings_leave') pass ### TNC events def tnc_connect(self): self.stack.set_visible_child_name('audio_input') self.stack.set_sensitive(True) self.sidebar.set_sensitive(True) self.serial_port_combo_box_text.set_sensitive(False) self.connect_button.set_label("gtk-disconnect") self.firmware_progress_bar.set_text("Select firmware image...") def tnc_disconnect(self): self.stack.set_visible_child_name('about') self.stack.set_sensitive(False) self.sidebar.set_sensitive(False) self.serial_port_combo_box_text.set_sensitive(True) self.connect_button.set_label("gtk-connect") self.connect_button.set_active(False) self.tnc = None self.modem_type = None ### Audio Input def tnc_rx_volume(self, value): self.audio_input_level_bar.set_value(min(10, int(value * 1.25 + .5))) def tnc_input_atten(self, value): self.input_attenuation_box.set_visible(True) self.input_attenuation_check_button.set_active(value > 0) def tnc_input_gain(self, value): self.input_gain_box.set_visible(True) self.input_gain_scale.set_value(value) def tnc_input_twist(self, value): self.input_twist_box.set_visible(True) self.input_twist_scale.set_value(value) def tnc_min_input_twist(self, value): self.input_twist_min_label.set_text("{}dB".format(value)) def tnc_max_input_twist(self, value): self.input_twist_max_label.set_text("{}dB".format(value)) def tnc_min_input_gain(self, value): self.input_gain_min_label.set_text("{}".format(value)) def tnc_max_input_gain(self, value): self.input_gain_max_label.set_text("{}".format(value)) def tnc_adjust_input(self): self.input_auto_adjust_button.set_visible(True) self.input_auto_adjust_button.set_sensitive(True) ### Audio Output def tnc_ptt_style(self, value): self.ptt_style_box.set_visible(True) if value == 0: self.ptt_simplex_radio_button.set_active(True) else: self.ptt_multiplex_radio_button.set_active(True) def tnc_tx_volume(self, gain): self.output_gain_scale.set_value(gain) def tnc_tx_twist(self, gain): self.output_twist_box.set_visible(True) self.output_twist_scale.set_value(gain) ### Power Settings def tnc_battery_level(self, value): self.power_settings_frame.set_visible(True) self.battery_voltage_label.set_text(str(int(value)) + "mV") level_bar_value = min(max(0, value - 3300) / 90.0, 10.0) self.battery_level_bar.set_value(level_bar_value) def tnc_power_on(self, value): self.power_settings_frame.set_visible(True) self.power_on_check_button.set_sensitive(True) self.power_on_check_button.set_active(value) def tnc_power_off(self, value): self.power_settings_frame.set_visible(True) self.power_off_check_button.set_sensitive(True) self.power_off_check_button.set_active(value) ### KISS Parameters def tnc_tx_delay(self, value): self.tx_delay_spin_button.set_value(value) def tnc_slot_time(self, value): self.slot_time_spin_button.set_value(value) def tnc_persistence(self, value): self.p_persist_spin_button.set_value(value) def tnc_tx_tail(self, value): # No longer used or settable pass def tnc_duplex(self, value): self.full_duplex_check_button.set_sensitive(True) self.full_duplex_check_button.set_active(value) ### Modem Settings def tnc_dcd(self, value): self.modem_settings_frame.set_visible(True) self.dcd_check_button.set_sensitive(True) self.dcd_check_button.set_active(value == 0) def tnc_conn_track(self, value): self.modem_settings_frame.set_visible(True) self.connection_tracking_check_button.set_sensitive(True) self.connection_tracking_check_button.set_active(value) def tnc_verbose(self, value): self.modem_settings_frame.set_visible(True) self.verbose_output_check_button.set_sensitive(True) self.verbose_output_check_button.set_active(value) def tnc_supported_modem_types(self, value): self.modem_settings_frame.set_visible(True) self.modem_type_combo_box_text.remove_all() self.supported_modem_types = {} for i, v in enumerate(value): if v in self.modem_types: self.supported_modem_types[v] = i self.modem_type_combo_box_text.append_text(self.modem_types[v]) if self.modem_type is not None: self.modem_type_combo_box_text.set_active( self.supported_modem_types[self.modem_type]) self.modem_type_combo_box_text.set_visible(True) self.modem_type_combo_box_text.set_sensitive(True) def tnc_selected_modem_type(self, value): print("selected modem type is %d = %s" % (value, self.modem_types[value])) self.modem_settings_frame.set_visible(True) self.modem_type_combo_box_text.set_sensitive(True) self.modem_type = value if value in self.modem_types and value in self.supported_modem_types and self.modem_type_combo_box_text.get_visible( ): self.modem_type_combo_box_text.set_active( self.supported_modem_types[self.modem_type]) def tnc_rx_reverse_polarity(self, value): self.modem_settings_frame.set_visible(True) self.rx_reverse_polarity_check_button.set_active(value) self.rx_reverse_polarity_check_button.set_visible(True) self.rx_reverse_polarity_check_button.set_sensitive(True) def tnc_tx_reverse_polarity(self, value): self.modem_settings_frame.set_visible(True) self.tx_reverse_polarity_check_button.set_active(value) self.tx_reverse_polarity_check_button.set_visible(True) self.tx_reverse_polarity_check_button.set_sensitive(True) def tnc_passall(self, value): self.modem_settings_frame.set_visible(True) self.passall_check_button.set_visible(True) self.passall_check_button.set_sensitive(True) self.passall_check_button.set_active(value) ### TNC Information def tnc_hardware_version(self, value): self.hardware_version_label.set_text(value) def tnc_firmware_version(self, value): self.firmware_version_label.set_text(value) self.firmware_update_version_label.set_text(value) def tnc_mac_address(self, value): self.mac_address_label.set_text(value) def tnc_serial_number(self, value): self.serial_number_label.set_text(value) def tnc_date_time(self, value): self.date_time_label.set_text(value) ### Update Firmware def tnc_dfu_firmware(self): self.update_firmware_frame.set_visible(False) ### Save Settings def tnc_eeprom_save(self): self.save_settings_frame.set_visible(True) self.save_settings_button.set_sensitive(True) def do_exception_dialog(self, ex): confirm = Gtk.MessageDialog(parent=self.main_window, flags=0, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=str(ex)) confirm.set_title("Error") confirm.run() confirm.destroy() def exception(self, ex): # print(str(ex)) GLib.idle_add(self.do_exception_dialog, ex) ### Firmware Update Callbacks def is_firmware_update_complete(self): return self.firmware_upload_complete is not None def firmware_set_steps(self, steps): self.progress_bar_step = 1.0 / steps # print("progress bar step: {}".format(self.progress_bar_step)) GLib.idle_add(self.firmware_progress_bar.set_pulse_step, self.progress_bar_step) def firmware_writing(self): self.progress_bar_progress = 0.0 GLib.idle_add(self.firmware_progress_bar.set_text, "Writing...") GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_verifying(self): self.progress_bar_progress = 0.0 GLib.idle_add(self.firmware_progress_bar.set_text, "Verifying...") GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_pulse(self): self.progress_bar_progress += self.progress_bar_step # Pulse doesn't work for some unknown reason # GLib.idle_add(self.firmware_progress_bar.pulse) GLib.idle_add(self.firmware_progress_bar.set_fraction, self.progress_bar_progress) def firmware_success(self): self.firmware_upload_complete = True # self.firmware_progress_bar.set_text("Firmware upload complete") # self.sidebar.set_sensitive(True) # self.tnc.disconnect() def firmware_failure(self, msg): self.firmware_upload_complete = False self.firmware_upload_msg = msg # self.firmware_progress_bar.set_text("Firmware upload failed") # self.sidebar.set_sensitive(True) def firmware_success_dialog(self): notify = Gtk.MessageDialog(parent=self.main_window, flags=0, message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, text="Firmware upload complete") notify.set_title("Firmware Update") notify.run() notify.destroy() def firmware_failure_dialog(self): notify = Gtk.MessageDialog(parent=self.main_window, flags=0, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text="Firmware upload failed: {}".format( self.firmware_upload_msg)) notify.set_title("Firmware Update") notify.run() notify.destroy() def check_firmware_upload_complete(self): if not self.is_firmware_update_complete(): self.firmware_gui_tag = GLib.timeout_add( 1, self.check_firmware_upload_complete) return if self.firmware_upload_complete: self.firmware_progress_bar.set_text("Firmware upload complete") self.firmware_success_dialog() # self.tnc.disconnect() else: self.firmware_progress_bar.set_text("Firmware upload failed") self.firmware_failure_dialog() self.tnc.upload_firmware_complete() self.stack.set_visible_child_name('audio_input') self.stack.set_sensitive(True) self.sidebar.set_sensitive(True)