$search
00001 from __future__ import with_statement 00002 import roslib; roslib.load_manifest("multi_interface_roam") 00003 import rospy 00004 import wpa_supplicant_node.msg as wpa_msgs 00005 import actionlib 00006 import state_publisher 00007 import mac_addr 00008 import event 00009 import threading 00010 from twisted.internet.defer import Deferred 00011 from twisted.internet import reactor 00012 from async_helpers import mainThreadCallback 00013 00014 class Network: 00015 def __init__(self, id, enabled, parameters): 00016 self.id = id 00017 self.enabled = enabled 00018 if type(parameters) != dict: 00019 # assume it is a message 00020 parameters = dict((p.key, p.value) for p in parameters) 00021 self.parameters = parameters 00022 self.__getitem__ = parameters.__getitem__ 00023 try: 00024 self.ssid = self['ssid'][1:-1] 00025 except KeyError: 00026 self.ssid = None 00027 00028 class AssociationState(type): 00029 def __new__(meta, classname, bases, classDict): 00030 return type.__new__(meta, classname, bases, classDict) 00031 def __nonzero__(cls): 00032 return False 00033 00034 class Associating(object): 00035 __metaclass__ = AssociationState 00036 00037 class Unassociated(object): 00038 __metaclass__ = AssociationState 00039 00040 def is_not_associating(state): 00041 print state, id(state), id(Associating) 00042 return state != Associating 00043 00044 class Radio: 00045 def __init__(self, interface_name): 00046 self.interface_name = interface_name 00047 self._last_assoc_msg = None 00048 self._associating = False 00049 self.associated = state_publisher.StatePublisher(Unassociated) 00050 self.frequency_list = state_publisher.StatePublisher([]) 00051 self.network_list = state_publisher.StatePublisher([]) 00052 self.scan_results_event = event.Event() 00053 self.scanning = state_publisher.StatePublisher(False) 00054 self.mutex = threading.Lock() 00055 00056 #def debug_assoc(iface, old_state, new_state): 00057 # print "Assoc change", iface, new_state 00058 #self.associated.subscribe(debug_assoc, interface_name) 00059 00060 self.networks = [] 00061 self.hidden_networks = [] 00062 self.raw_scan_results = [] 00063 self.scan_results = [] 00064 self.scan_deferred = None 00065 00066 prefix = rospy.resolve_name("wifi")+"/"+interface_name+"/" 00067 rospy.Subscriber(prefix + "scan_results", wpa_msgs.ScanResult, self._scan_results_callback) 00068 rospy.Subscriber(prefix + "network_list", wpa_msgs.NetworkList, self._network_list_callback) 00069 rospy.Subscriber(prefix + "frequency_list", wpa_msgs.FrequencyList, self._frequency_list_callback) 00070 self._scan_action = actionlib.SimpleActionClient(prefix+"scan", wpa_msgs.ScanAction) 00071 self._associate_action = actionlib.SimpleActionClient(prefix+"associate", wpa_msgs.AssociateAction) 00072 00073 def is_scanning(self): 00074 return _scan_action.simple_state == SimpleGoalState.DONE 00075 00076 def scan(self, freqs = [], ssids = []): 00077 goal = wpa_msgs.ScanGoal() 00078 for s in ssids: 00079 goal.ssids.append(s) 00080 for f in freqs: 00081 goal.frequencies.append(f) 00082 #print "scan goal", goal 00083 self._scan_action.send_goal(goal, done_cb = self._scan_done_callback) 00084 self.scanning.set(True) 00085 self.scan_deferred = Deferred() 00086 return self.scan_deferred 00087 00088 def cancel_scans(self): 00089 self.scanning = False 00090 _scan_action.cancel_all_goals() 00091 00092 def associate(self, id): 00093 print "radio.associate", self.interface_name 00094 ssid = id[0] 00095 bssid = mac_addr.to_packed(id[1]) 00096 with self.mutex: 00097 self._associate_action.send_goal(wpa_msgs.AssociateGoal(ssid, bssid), 00098 done_cb = self._assoc_done_cb, 00099 feedback_cb = self._assoc_feedback_cb) 00100 self.associated.set(Associating) 00101 00102 def unassociate(self): 00103 self._associate_action.cancel_all_goals() 00104 00105 @mainThreadCallback 00106 def _assoc_feedback_cb(self, fbk): 00107 print "_assoc_feedback_cb", self.interface_name, fbk.associated 00108 if fbk.associated: 00109 self.associated.set(fbk.bss) 00110 00111 def _assoc_done_cb(self, state, rslt): 00112 # DANGER, this is not run in the main thread!! 00113 00114 print "_assoc_done_cb", self.interface_name 00115 # Make sure that no feedback for this goal will arrive after we 00116 # have processed the goal. 00117 with self.mutex: 00118 self._associate_action.stop_tracking_goal() 00119 reactor.callFromThread(self.associated.set, Unassociated) 00120 00121 @mainThreadCallback 00122 def _scan_done_callback(self, state, rslt): 00123 """Called when all our scans are done.""" 00124 self.scanning.set(False) 00125 if self.scan_deferred: 00126 self.scan_deferred.callback(rslt.success) 00127 self.scan_deferred = None 00128 00129 @mainThreadCallback 00130 def _frequency_list_callback(self, msg): 00131 self.frequency_list.set(msg.frequencies) 00132 00133 @mainThreadCallback 00134 def _network_list_callback(self, msg): 00135 self.networks = [ Network(net.network_id, net.enabled, net.parameters) for net in msg.networks ] 00136 self.hidden_networks = [ net for net in self.networks if net.parameters['scan_ssid'] == '1' ] 00137 self.network_list.set(self.networks) 00138 self._filter_raw_scan_results() # The filtered scan results are out of date. 00139 00140 def enabled_bss(self, bss): 00141 for net in self.networks: 00142 # @todo This check will not work for <any> netwoks. FIXME 00143 # @todo Might want to check that security parameters match too. FIXME 00144 if net.ssid == bss.ssid: 00145 return True 00146 return False 00147 00148 def _filter_raw_scan_results(self): 00149 self.scan_results = [ bss for bss in self.raw_scan_results if self.enabled_bss(bss) ] 00150 self.scan_results = filter(lambda bss: bss.frequency in self.frequency_list.get(), self.scan_results) 00151 self.scan_results_event.trigger(self.scan_results) 00152 00153 @mainThreadCallback 00154 def _scan_results_callback(self, msg): 00155 self.raw_scan_results = msg.bss 00156 self._filter_raw_scan_results() 00157