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 from twisted.internet.defer import Deferred
00010 from twisted.internet import reactor
00011 from async_helpers import mainThreadCallback
00012
00013 class Network:
00014 def __init__(self, id, enabled, parameters):
00015 self.id = id
00016 self.enabled = enabled
00017 if type(parameters) != dict:
00018
00019 parameters = dict((p.key, p.value) for p in parameters)
00020 self.parameters = parameters
00021 self.__getitem__ = parameters.__getitem__
00022 try:
00023 self.ssid = self['ssid'][1:-1]
00024 except KeyError:
00025 self.ssid = None
00026
00027 class AssociationState(type):
00028 def __new__(meta, classname, bases, classDict):
00029 return type.__new__(meta, classname, bases, classDict)
00030 def __nonzero__(cls):
00031 return False
00032
00033 class Associating(object):
00034 __metaclass__ = AssociationState
00035
00036 class Unassociated(object):
00037 __metaclass__ = AssociationState
00038
00039 def is_not_associating(state):
00040 print state, id(state), id(Associating)
00041 return state != Associating
00042
00043 class Radio:
00044 def __init__(self, interface_name):
00045 self.interface_name = interface_name
00046 self._last_assoc_msg = None
00047 self._associating = False
00048 self.associated = state_publisher.StatePublisher(Unassociated)
00049 self.frequency_list = state_publisher.StatePublisher([])
00050 self.network_list = state_publisher.StatePublisher([])
00051 self.scan_results_event = event.Event()
00052 self.scanning = state_publisher.StatePublisher(False)
00053
00054
00055
00056
00057
00058 self.networks = []
00059 self.hidden_networks = []
00060 self.raw_scan_results = []
00061 self.scan_results = []
00062 self.scan_deferred = None
00063
00064 prefix = rospy.resolve_name("wifi")+"/"+interface_name+"/"
00065 rospy.Subscriber(prefix + "scan_results", wpa_msgs.ScanResult, self._scan_results_callback)
00066 rospy.Subscriber(prefix + "network_list", wpa_msgs.NetworkList, self._network_list_callback)
00067 rospy.Subscriber(prefix + "frequency_list", wpa_msgs.FrequencyList, self._frequency_list_callback)
00068 self._scan_action = actionlib.SimpleActionClient(prefix+"scan", wpa_msgs.ScanAction)
00069 self._associate_action = actionlib.SimpleActionClient(prefix+"associate", wpa_msgs.AssociateAction)
00070
00071 def is_scanning(self):
00072 return _scan_action.simple_state == SimpleGoalState.DONE
00073
00074 def scan(self, freqs = [], ssids = []):
00075 goal = wpa_msgs.ScanGoal()
00076 for s in ssids:
00077 goal.ssids.append(s)
00078 for f in freqs:
00079 goal.frequencies.append(f)
00080
00081 self._scan_action.send_goal(goal, done_cb = self._scan_done_callback)
00082 self.scanning.set(True)
00083 self.scan_deferred = Deferred()
00084 return self.scan_deferred
00085
00086 def cancel_scans(self):
00087 self.scanning = False
00088 _scan_action.cancel_all_goals()
00089
00090 def associate(self, id):
00091 ssid = id[0]
00092 bssid = mac_addr.to_packed(id[1])
00093 self._associate_action.send_goal(wpa_msgs.AssociateGoal(ssid, bssid),
00094 done_cb = self._assoc_done_cb,
00095 feedback_cb = self._assoc_feedback_cb)
00096 self.associated.set(Associating)
00097
00098 def unassociate(self):
00099 self._associate_action.cancel_all_goals()
00100
00101 @mainThreadCallback
00102 def _assoc_feedback_cb(self, fbk):
00103 if fbk.associated:
00104 self.associated.set(fbk.bss)
00105 else:
00106 self.associated.set(Associating)
00107
00108 @mainThreadCallback
00109 def _assoc_done_cb(self, state, rslt):
00110 self.associated.set(Unassociated)
00111
00112 @mainThreadCallback
00113 def _scan_done_callback(self, state, rslt):
00114 """Called when all our scans are done."""
00115 self.scanning.set(False)
00116 if self.scan_deferred:
00117 self.scan_deferred.callback(rslt.success)
00118 self.scan_deferred = None
00119
00120 @mainThreadCallback
00121 def _frequency_list_callback(self, msg):
00122 self.frequency_list.set(msg.frequencies)
00123
00124 @mainThreadCallback
00125 def _network_list_callback(self, msg):
00126 self.networks = [ Network(net.network_id, net.enabled, net.parameters) for net in msg.networks ]
00127 self.hidden_networks = [ net for net in self.networks if net.parameters['scan_ssid'] == '1' ]
00128 self.network_list.set(self.networks)
00129 self._filter_raw_scan_results()
00130
00131 def enabled_bss(self, bss):
00132 for net in self.networks:
00133
00134
00135 if net.ssid == bss.ssid:
00136 return True
00137 return False
00138
00139 def _filter_raw_scan_results(self):
00140 self.scan_results = [ bss for bss in self.raw_scan_results if self.enabled_bss(bss) ]
00141 self.scan_results_event.trigger(self.scan_results)
00142
00143 @mainThreadCallback
00144 def _scan_results_callback(self, msg):
00145 self.raw_scan_results = msg.bss
00146 self._filter_raw_scan_results()
00147