radio_sm.py
Go to the documentation of this file.
00001 from __future__ import with_statement
00002 import radio
00003 from netlink_monitor import netlink_monitor, IFSTATE
00004 import async_helpers
00005 import asmach as smach
00006 from twisted.internet import reactor
00007 from twisted.internet.defer import inlineCallbacks, returnValue
00008 import state_publisher
00009 import operator
00010 import event
00011 
00012 class RadioSmData:
00013     def __init__(self, iface_name):
00014         self._radio = radio.Radio(iface_name)
00015         self.iface_name = iface_name
00016         self._up_state_pub = netlink_monitor.get_state_publisher(iface_name, IFSTATE.UP)
00017         self.activate_request = state_publisher.StatePublisher(False)
00018         self.is_active = state_publisher.StatePublisher(False)
00019         self.scanning_enabled = state_publisher.StatePublisher(False)
00020         self.associate_request = event.Event()
00021         self.disactivate_delay = 1
00022         self.pre_up_sleep = 1
00023         
00024         # Copy radio members that we are willing to expose
00025         self.unassociate = self._radio.unassociate
00026         self.associated = self._radio.associated
00027         self.scanning = self._radio.scanning
00028         self.scan = self._radio.scan
00029         self.scan_results_event = self._radio.scan_results_event
00030         self.frequency_list = self._radio.frequency_list
00031 
00032 class RadioSmState(smach.State):
00033     def __init__(self, *args, **kwargs):
00034         smach.State.__init__(self, input_keys=['radio'], output_keys=['radio'], *args, **kwargs)
00035 
00036 class Down(RadioSmState):
00037     def __init__(self):
00038         RadioSmState.__init__(self, outcomes=['up'])
00039     
00040     @inlineCallbacks
00041     def execute_async(self, ud):
00042         # Wait a bit here because buggy drivers don't like to do things
00043         # just as they are coming down.
00044         yield async_helpers.async_sleep(ud.radio.pre_up_sleep)
00045         yield async_helpers.wait_for_state(ud.radio._up_state_pub, operator.truth)
00046         returnValue('up')
00047 
00048 class Unassociated(RadioSmState):
00049     def __init__(self):
00050         RadioSmState.__init__(self, outcomes=['associate', 'down'])
00051     
00052     @inlineCallbacks
00053     def execute_async(self, ud):
00054         # If we got here then were forcibly disactivated, and the previous
00055         # activation request is moot.
00056         ud.radio.activate_request.set(False)
00057 
00058         # We may have landed here after the interface went down causing
00059         # disassociation. Quickly check for that before getting to work.
00060         if not ud.radio._up_state_pub.get():
00061             returnValue('down')
00062         
00063         # Use callLater so that no association request will arrive before
00064         # we select.
00065         reactor.callLater(0, ud.radio.scanning_enabled.set, True)
00066         assoc_event_stream = async_helpers.EventStream(ud.radio.associate_request)
00067         events = yield async_helpers.select(
00068                 async_helpers.StateCondition(ud.radio._up_state_pub, operator.__not__ ),
00069                 assoc_event_stream
00070                 )
00071         ud.radio.scanning_enabled.set(False)
00072 
00073         if 1 in events:
00074             ud.radio.requested_bss = assoc_event_stream.get()
00075             returnValue('associate')
00076         returnValue('down')
00077 
00078 class Associating(RadioSmState):
00079     def __init__(self):
00080         RadioSmState.__init__(self, outcomes=['associated', 'failed'])
00081     
00082     @inlineCallbacks
00083     def execute_async(self, ud):
00084         ud.radio._radio.associate(*ud.radio.requested_bss[0], **ud.radio.requested_bss[1])
00085         
00086         #print "Associating before", ud.radio.associated.get()
00087         events = yield async_helpers.select(
00088                 async_helpers.StateCondition(ud.radio._up_state_pub, operator.__not__ ),
00089                 async_helpers.StateCondition(ud.radio._radio.associated, lambda x: x != radio.Associating))
00090 
00091         if 0 in events or ud.radio.associated.get() == radio.Unassociated:
00092             returnValue('failed')
00093         else:
00094             #print "Associated", ud.radio.iface_name, ud.radio.associated.get()
00095             returnValue('associated')
00096 
00097 class Associated(RadioSmState):
00098     def __init__(self):
00099         RadioSmState.__init__(self, outcomes=['activate', 'reassociate', 'unassociated'])
00100     
00101     @inlineCallbacks
00102     def execute_async(self, ud):
00103         # Use callLater so that no association request will arrive before
00104         # we select.
00105         reactor.callLater(0, ud.radio.scanning_enabled.set, True)
00106         assoc_event_stream = async_helpers.EventStream(ud.radio.associate_request)
00107         #print "Associated before", ud.radio.associated.get()
00108         events = yield async_helpers.select(
00109                 async_helpers.StateCondition(ud.radio._up_state_pub, operator.__not__ ),
00110                 async_helpers.StateCondition(ud.radio.activate_request, operator.truth),
00111                 assoc_event_stream,
00112                 )
00113         ud.radio.scanning_enabled.set(False)
00114 
00115         if 1 in events:
00116             returnValue('activate')
00117         if 2 in events:
00118             ud.radio.requested_bss = assoc_event_stream.get()
00119             #print "Assoc changed", ud.radio.iface_name, ud.radio.requested_bss
00120             returnValue('reassociate')
00121         returnValue('unassociated')
00122 
00123 class Active(RadioSmState):
00124     def __init__(self):
00125         RadioSmState.__init__(self, outcomes=['disactivate', 'unassociated'])
00126     
00127     @inlineCallbacks
00128     def execute_async(self, ud):
00129         events = yield async_helpers.select(
00130           async_helpers.StateCondition(ud.radio.activate_request, operator.__not__),
00131           async_helpers.StateCondition(ud.radio.associated, operator.__not__))
00132         if 0 in events:
00133             returnValue('disactivate')
00134         returnValue('unassociated')
00135 
00136 class Disactivating(RadioSmState):
00137     def __init__(self):
00138         RadioSmState.__init__(self, outcomes=['done', 'activate', 'unassociated'])
00139 
00140     @inlineCallbacks
00141     def execute_async(self, ud):
00142         events = yield async_helpers.select(
00143           async_helpers.Timeout(ud.radio.disactivate_delay),
00144           async_helpers.StateCondition(ud.radio.activate_request, operator.truth),
00145           async_helpers.StateCondition(ud.radio.associated, operator.__not__))
00146         if 1 in events:
00147             returnValue('activate')
00148         if 2 in events:
00149             returnValue('unassociated')
00150         returnValue('done')
00151 
00152 def _state_change_cb(ud, states):
00153     ud.radio.is_active.set("ACTIVE" in states)
00154 
00155 def radio_sm(iface):
00156     sm = smach.StateMachine(outcomes=[], input_keys=['radio'])
00157     smadd = smach.StateMachine.add
00158     with sm:
00159         smadd('DOWN', Down(),  transitions = { 'up' : 'UNASSOCIATED' })
00160         smadd('UNASSOCIATED', Unassociated(), transitions = { 'associate' : 'ASSOCIATING', 'down' : 'DOWN'})
00161         smadd('ASSOCIATING', Associating(), transitions = { 'associated' : 'ASSOCIATED', 'failed' : 'DOWN'})
00162         smadd('ASSOCIATED', Associated(), transitions = { 'reassociate' : 'ASSOCIATING', 'activate' : 'ACTIVE', 'unassociated' : 'DOWN'})
00163         smadd('ACTIVE', Active(), transitions = { 'disactivate' : 'DISACTIVATING', 'unassociated' : 'DOWN'} )
00164         smadd('DISACTIVATING', Disactivating(), transitions = { 'done' : 'ASSOCIATED', 'activate' : 'ACTIVE', 'unassociated' : 'DOWN'} )
00165     ud = smach.UserData()
00166     ud.radio = RadioSmData(iface)
00167     sm.register_transition_cb(_state_change_cb)
00168     sm.execute_async(ud)
00169     return ud.radio


multi_interface_roam
Author(s): Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:15