From 7cb482a9fcf76bf080a960b63a00b1d98153ba51 Mon Sep 17 00:00:00 2001 From: David Paleino Date: Thu, 27 Sep 2012 22:18:04 +0200 Subject: [PATCH] Implement iwconfig bitrate setting --- curses/netentry_curses.py | 24 ++++++++++++++++++++- gtk/guiutil.py | 37 ++++++++++++++++++++++++++++++++ gtk/netentry.py | 32 ++++++++++++++++++++++++++-- wicd/networking.py | 20 +++++++++++++++--- wicd/wicd-daemon.py | 19 +++++++++++++++++ wicd/wnettools.py | 44 +++++++++++++++++++++++++++++++++++---- 6 files changed, 166 insertions(+), 10 deletions(-) diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 37359f6..ec6bcc9 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -372,13 +372,21 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): global_settings_t = _('Use these settings for all networks sharing this essid') encryption_t = _('Use Encryption') autoconnect_t = _('Automatically connect to this network') + bitrate_t = _('Wireless bitrate') + allow_lower_bitrates_t = _('Allow lower bitrates') self.global_settings_chkbox = urwid.CheckBox(global_settings_t) self.encryption_chkbox = urwid.CheckBox(encryption_t,on_state_change=self.encryption_toggle) self.encryption_combo = ComboBox(callback=self.combo_on_change) self.autoconnect_chkbox = urwid.CheckBox(autoconnect_t) + self.bitrate_combo = ComboBox(bitrate_t) + self.allow_lower_bitrates_chkbox = urwid.CheckBox(allow_lower_bitrates_t) + self.pile_encrypt = None # _w is a Frame, _w.body is a ListBox, _w.body.body is the ListWalker :-) + self._listbox.body.append(self.bitrate_combo) + self._listbox.body.append(self.allow_lower_bitrates_chkbox) + self._listbox.body.append(urwid.Text('')) self._listbox.body.append(self.global_settings_chkbox) self._listbox.body.append(self.autoconnect_chkbox) self._listbox.body.append(self.encryption_chkbox) @@ -411,6 +419,12 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.autoconnect_chkbox.set_state(to_bool(self.format_entry(networkID, "automatic"))) + self.bitrates = wireless.GetAvailableBitrates() + self.bitrates.append('auto') + self.bitrate_combo.set_list(self.bitrates) + self.bitrate_combo.set_focus(self.bitrates.index(wireless.GetWirelessProperty(networkID, 'bitrate'))) + self.allow_lower_bitrates_chkbox.set_state(to_bool(self.format_entry(networkID, 'allow_lower_bitrates'))) + #self.reset_static_checkboxes() self.encryption_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID, 'encryption')),do_callback=False) @@ -490,6 +504,14 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): else: self.set_net_prop('use_settings_globally', False) wireless.RemoveGlobalEssidEntry(self.networkid) - + + self.set_net_prop('bitrate', self.bitrates[self.bitrate_combo.get_focus()[1]]) + self.set_net_prop('allow_lower_bitrates', self.allow_lower_bitrates_chkbox.get_state()) wireless.SaveWirelessNetworkProfile(self.networkid) return True + + def ready_widgets(self, ui, body): + AdvancedSettingsDialog.ready_widgets(self, ui, body) + self.ui = ui + self.body = body + self.bitrate_combo.build_combobox(body, ui, 17) diff --git a/gtk/guiutil.py b/gtk/guiutil.py index 484eab5..2a97538 100644 --- a/gtk/guiutil.py +++ b/gtk/guiutil.py @@ -216,3 +216,40 @@ class ProtectedLabelEntry(gtk.HBox): def click_handler(self, widget=None, event=None): active = self.check.get_active() self.entry.set_visibility(active) + +class LabelCombo(gtk.HBox): + """ A label on the left with a combobox on the right. """ + def __init__(self,text): + gtk.HBox.__init__(self) + self.combo = gtk.ComboBox() + self.combo.set_size_request(200, -1) + self.label = LeftAlignedLabel() + self.label.set_text(text) + self.label.set_size_request(170, -1) + cell = gtk.CellRendererText() + self.combo.pack_start(cell, True) + self.combo.add_attribute(cell, 'text', 0) + self.pack_start(self.label, fill=True, expand=True) + self.pack_start(self.combo, fill=False, expand=False) + self.label.show() + self.combo.show() + self.show() + + def get_active(self): + return self.combo.get_active() + + def set_active(self, index): + self.combo.set_active(index) + + def get_active_text(self): + return self.combo.get_active_text() + + def get_model(self): + return self.combo.get_model() + + def set_model(self, model=None): + self.combo.set_model(model) + + def set_sensitive(self, value): + self.combo.set_sensitive(value) + self.label.set_sensitive(value) diff --git a/gtk/netentry.py b/gtk/netentry.py index 2a7efe9..183a3e6 100644 --- a/gtk/netentry.py +++ b/gtk/netentry.py @@ -31,7 +31,7 @@ import wicd.misc as misc import wicd.wpath as wpath import wicd.dbusmanager as dbusmanager from wicd.misc import noneToString, stringToNone, noneToBlankString, to_bool -from guiutil import error, LabelEntry, GreyLabel, LeftAlignedLabel, string_input, ProtectedLabelEntry +from guiutil import error, LabelEntry, GreyLabel, LeftAlignedLabel, string_input, ProtectedLabelEntry, LabelCombo from wicd.translations import language, _ @@ -466,6 +466,20 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.combo_encryption = gtk.combo_box_new_text() self.chkbox_encryption = gtk.CheckButton(_('Use Encryption')) self.chkbox_global_settings = gtk.CheckButton(_('Use these settings for all networks sharing this essid')) + + rate_vbox = gtk.VBox(False, 0) + + self.combo_rate = LabelCombo(_('Wireless bitrate')) + rates = gtk.ListStore(str) + self.bitrates = wireless.GetAvailableBitrates() + self.bitrates.append('auto') + for br in self.bitrates: + rates.append((br,)) + self.combo_rate.set_model(rates) + self.chkbox_lower_rate = gtk.CheckButton(_('Allow lower bitrates')) + rate_vbox.pack_start(self.combo_rate) + rate_vbox.pack_start(self.chkbox_lower_rate) + # Make the vbox to hold the encryption stuff. self.vbox_encrypt_info = gtk.VBox(False, 0) self.toggle_encryption() @@ -493,6 +507,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.combo_encryption.set_active(0) self.change_encrypt_method() + self.cvbox.pack_start(rate_vbox, False, False) self.cvbox.pack_start(self.chkbox_global_settings, False, False) self.cvbox.pack_start(self.chkbox_encryption, False, False) self.cvbox.pack_start(self.combo_encryption, False, False) @@ -567,6 +582,14 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.toggle_dhcp_hostname_checkbox() + # TODO: get the value from the config + chosen_bitrate = wireless.GetWirelessProperty(networkID, 'bitrate') + if chosen_bitrate not in self.bitrates: + chosen_bitrate = 'auto' + self.combo_rate.set_active(self.bitrates.index(chosen_bitrate)) + self.chkbox_lower_rate.set_active(bool(wireless.GetWirelessProperty(networkID, + 'allow_lower_bitrates'))) + activeID = -1 # Set the menu to this item when we are done user_enctype = wireless.GetWirelessProperty(networkID, "enctype") for x, enc_type in enumerate(self.encrypt_types): @@ -617,7 +640,12 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): else: self.set_net_prop('use_settings_globally', False) wireless.RemoveGlobalEssidEntry(networkid) - + + if self.combo_rate.get_active() == -1: + self.set_net_prop('bitrate', 'auto') + else: + self.set_net_prop('bitrate', self.bitrates[self.combo_rate.get_active()]) + self.set_net_prop('allow_lower_bitrates', bool(self.chkbox_lower_rate.get_active())) wireless.SaveWirelessNetworkProfile(networkid) return True diff --git a/wicd/networking.py b/wicd/networking.py index ff9563f..ced94b6 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -634,7 +634,8 @@ class Wireless(Controller): self.after_script, self.pre_disconnect_script, self.post_disconnect_script, self.global_dns_1, self.global_dns_2, self.global_dns_3, self.global_dns_dom, - self.global_search_dom, self.wiface, self.should_verify_ap, debug) + self.global_search_dom, self.wiface, self.should_verify_ap, + self.bitrate, self.allow_lower_bitrates, debug) self.connecting_thread.setDaemon(True) self.connecting_thread.start() return True @@ -708,6 +709,15 @@ class Wireless(Controller): """ return self.wiface.GetAvailableAuthMethods(iwlistauth) + def GetAvailableBitrates(self): + """ Get the available bitrates for the interface. + + Returns: + The available bitrates of the interface as a string, or None if the + bitrates can't be found. + """ + return self.wiface.GetAvailableBitrates() + def GetIwconfig(self): """ Get the out of iwconfig. """ return self.wiface.GetIwconfig() @@ -838,7 +848,7 @@ class WirelessConnectThread(ConnectThread): def __init__(self, network, wireless, wpa_driver, before_script, after_script, pre_disconnect_script, post_disconnect_script, gdns1, gdns2, gdns3, gdns_dom, gsearch_dom, wiface, - should_verify_ap, debug=False): + should_verify_ap, bitrate, allow_lower_bitrates, debug=False): """ Initialise the thread with network information. Keyword arguments: @@ -852,6 +862,8 @@ class WirelessConnectThread(ConnectThread): gdns1 -- global DNS server 1 gdns2 -- global DNS server 2 gdns3 -- global DNS server 3 + bitrate -- chosen interface bitrate + allow_lower_bitrates -- whether to allow lower bitrates or not """ ConnectThread.__init__(self, network, wireless, before_script, @@ -860,7 +872,8 @@ class WirelessConnectThread(ConnectThread): gdns3, gdns_dom, gsearch_dom, wiface, debug) self.wpa_driver = wpa_driver self.should_verify_ap = should_verify_ap - + self.bitrate = bitrate + self.allow_lower_bitrates = allow_lower_bitrates def _connect(self): """ The main function of the connection thread. @@ -896,6 +909,7 @@ class WirelessConnectThread(ConnectThread): self.stop_wpa(wiface) self.flush_routes(wiface) wiface.SetMode(self.network['mode']) + wiface.SetBitrate(self.bitrate, self.allow_lower_bitrates) # Put interface up. self.SetStatus('configuring_interface') diff --git a/wicd/wicd-daemon.py b/wicd/wicd-daemon.py index e510038..2c45bc2 100644 --- a/wicd/wicd-daemon.py +++ b/wicd/wicd-daemon.py @@ -1029,6 +1029,22 @@ class WirelessDaemon(dbus.service.Object): """ Returns the operational mode for the iwlistauth parameter """ return misc.to_unicode(self.wifi.GetAvailableAuthMethods(iwlistauth)) + @dbus.service.method('org.wicd.daemon.wireless') + def GetAvailableBitrates(self): + """ Returns the available bitrates the wifi card can use """ + return self.wifi.GetAvailableBitrates() + + @dbus.service.method('org.wicd.daemon.wireless') + def GetOperableBitrates(self, networkid): + """ Returns the real bitrates a connection to a network can use. + + This is the intersection between the bitrates the AP can transmit to, + and the bitrates the wireless card can use. + """ + a = set(self.GetAvailableBitrates()) + b = set(self.GetWirelessProperty(networkid, 'bitrates')) + return sorted(list(a & b), lambda x, y: int(float(x) - float(y))) + @dbus.service.method('org.wicd.daemon.wireless') def CreateAdHocNetwork(self, essid, channel, ip, enctype, key, encused, ics): @@ -1157,6 +1173,9 @@ class WirelessDaemon(dbus.service.Object): 'predisconnectscript') self.wifi.post_disconnect_script = self.GetWirelessProperty(id, 'postdisconnectscript') + self.wifi.bitrate = self.GetWirelessProperty(id, 'bitrate') + self.wifi.allow_lower_bitrates = self.GetWirelessProperty(id, + 'allow_lower_bitrates') print 'Connecting to wireless network ' + str(self.LastScan[id]['essid']) # disconnect to make sure that scripts are run self.wifi.Disconnect() diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 477fe67..67e7a0e 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -36,6 +36,7 @@ import re import random import time from string import maketrans, translate +import dbus import wpath import misc @@ -49,7 +50,7 @@ channel_pattern = re.compile('.*Channel:?=? ?(\d+)', _re_mode) strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode) altstrength_pattern = re.compile('.*Signal level:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode) signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', _re_mode) -bitrates_pattern = re.compile('(\d+\s+\S+/s)', _re_mode) +bitrates_pattern = re.compile('([\d\.]+)\s+\S+/s', _re_mode) mode_pattern = re.compile('.*Mode:([A-Za-z-]*?)\n', _re_mode) freq_pattern = re.compile('.*Frequency:(.*?)\n', _re_mode) wep_pattern = re.compile('.*Encryption key:(.*?)\n', _re_mode) @@ -1113,6 +1114,22 @@ class BaseWirelessInterface(BaseInterface): if self.verbose: print cmd misc.Run(cmd) + @neediface(False) + def SetBitrate(self, bitrate, allow_lower=False): + ''' Set the desired bitrate for the interface. + + Keyword arguments: + bitrate -- desired bitrate (string) + allow_lower -- whether to allow lower bitrates, or keep it fixed (bool) + ''' + # FIXME: what if, in future, bitrates won't be "M(egabit per second)" + #+anymore? + if allow_lower: + cmd = 'iwconfig %s rate %sM auto' % (self.iface, bitrate) + else: + cmd = 'iwconfig %s rate %sM fixed' % (self.iface, bitrate) + misc.Run(cmd) + @neediface(False) def Associate(self, essid, channel=None, bssid=None): """ Associate with the specified wireless network. @@ -1293,9 +1310,14 @@ class BaseWirelessInterface(BaseInterface): ap['channel'] = self._FreqToChannel(freq) # Bit Rate - ap['bitrates'] = misc.RunRegex(bitrates_pattern, - cell.split("Bit Rates")[-1]) - + bitrates = cell.split('Bit Rates')[-1].replace('\n', '; ') + m = re.findall(bitrates_pattern, bitrates) + if m: + # numeric sort + ap['bitrates'] = sorted(m, lambda x, y: int(float(x) - float(y))) + else: + ap['bitrates'] = None + # BSSID ap['bssid'] = misc.RunRegex(ap_mac_pattern, cell) @@ -1456,6 +1478,20 @@ class BaseWirelessInterface(BaseInterface): authm_list = [m.strip() for m in authm.split('\n') if m.strip()] return ';'.join(authm_list) + @neediface('') + def GetAvailableBitrates(self): + """ Get the available bitrates the wifi card can use. """ + + cmd = 'iwlist ' + self.iface + ' rate' + if self.verbose: print cmd + rates = misc.Run(cmd) + + # process the output + rates = rates.split('\n') + rates = filter(None, map(lambda x: x.strip().split(' ')[0], rates)) + rates = filter(lambda x: x[0].isdigit(), rates) + return dbus.Array(rates, signature='v') + def _get_link_quality(self, output): """ Parse out the link quality from iwlist scan or iwconfig output. """ try: