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
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
00043
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
00055
00056 ud.radio.activate_request.set(False)
00057
00058
00059
00060 if not ud.radio._up_state_pub.get():
00061 returnValue('down')
00062
00063
00064
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
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
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
00104
00105 reactor.callLater(0, ud.radio.scanning_enabled.set, True)
00106 assoc_event_stream = async_helpers.EventStream(ud.radio.associate_request)
00107
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
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