moved statemachine-related code to statemachine.py
This commit is contained in:
parent
60c899edcc
commit
c5d305295b
3 changed files with 345 additions and 367 deletions
|
@ -1,9 +1,8 @@
|
|||
|
||||
import csv
|
||||
import ConfigParser
|
||||
import apparatinterface
|
||||
import phoneinterface
|
||||
import fetapd
|
||||
import statemachine
|
||||
|
||||
class ConfigurationReader(object):
|
||||
DEFAULTS = {
|
||||
|
@ -82,7 +81,7 @@ class ConfigurationReader(object):
|
|||
invert_gs = self.__get_global_val_bool('invert_gs'),
|
||||
)
|
||||
|
||||
self.__dialconfig = fetapd.DialConfiguration(
|
||||
self.__dialconfig = statemachine.DialConfiguration(
|
||||
self.__get_global_val_int('dial_timeout'),
|
||||
self.__read_shortcuts(),
|
||||
self.__read_blacklist(),
|
||||
|
|
380
fetapd.py
380
fetapd.py
|
@ -1,370 +1,43 @@
|
|||
import time
|
||||
import threading
|
||||
import Queue as queue
|
||||
from phoneinterface import PhoneInterface, PhoneEvent
|
||||
from apparatinterface import FeApPinConfiguration, FeApUserInterface
|
||||
import configreader
|
||||
import statemachine
|
||||
|
||||
|
||||
class DialConfiguration(object):
|
||||
def __init__(self, dial_timeout, shortcuts, blacklist):
|
||||
self.dial_timeout = dial_timeout
|
||||
self.shortcuts = shortcuts
|
||||
self.blacklist = blacklist
|
||||
controller = None
|
||||
|
||||
class IllegalEventError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
An abstract state, needed to define all possible events.
|
||||
|
||||
"""
|
||||
class AbstractState(object):
|
||||
def on_registration_in_progress(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_registration_successful(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_registration_lost(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_incoming_call(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_ended(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_accepted(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_ringing(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_invalid_number(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_timeout(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def leave(self):
|
||||
return None
|
||||
|
||||
|
||||
"""
|
||||
The basic state that every other state inherits from. It defines default
|
||||
behaviour for some events (overriden if necessary).
|
||||
|
||||
"""
|
||||
class BaseState(AbstractState):
|
||||
def __init__(self, controller):
|
||||
self._controller = controller
|
||||
|
||||
def on_registration_lost(self):
|
||||
return InitState
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
return None
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return None
|
||||
|
||||
def on_incoming_call(self):
|
||||
self._controller.phone.decline_call()
|
||||
|
||||
def on_call_ended(self):
|
||||
# When an incoming call is declined, a call_ended event occurs, which
|
||||
# needs to be ignored, here.
|
||||
return None
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
return None
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
return None
|
||||
|
||||
|
||||
class InitState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(InitState, self).__init__(controller)
|
||||
self._controller.feap.set_schauzeichen(True)
|
||||
|
||||
def on_registration_in_progress(self):
|
||||
print('registration in progress')
|
||||
return RegisteringState
|
||||
|
||||
class RegisteringState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(RegisteringState, self).__init__(controller)
|
||||
|
||||
def on_registration_successful(self):
|
||||
print('registration successful')
|
||||
self._controller.feap.set_schauzeichen(False)
|
||||
return IdleState
|
||||
|
||||
class IdleState(BaseState):
|
||||
def on_incoming_call(self):
|
||||
print('incomfing call')
|
||||
caller = self._controller.phone.get_remote_number()
|
||||
print('From: %s' % caller)
|
||||
if caller in self._controller.dialconfig.blacklist:
|
||||
print('Caller on blacklist - declining')
|
||||
self._controller.phone.decline_call()
|
||||
return CallTerminatingState
|
||||
else:
|
||||
return SchelltState
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
print('gabel up')
|
||||
return DialingState
|
||||
|
||||
class SchelltState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(SchelltState, self).__init__(controller)
|
||||
self._controller.feap.set_wecker(True)
|
||||
|
||||
def leave(self):
|
||||
self._controller.feap.set_wecker(False)
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
return AcceptingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return IdleState
|
||||
|
||||
class AcceptingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(AcceptingState, self).__init__(controller)
|
||||
self._controller.phone.accept_call()
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
class CallTerminatingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(CallTerminatingState, self).__init__(controller)
|
||||
self._controller.phone.end_call()
|
||||
|
||||
def on_call_ended(self):
|
||||
return IdleState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return None
|
||||
|
||||
class ForgottenState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
class BusyBeepingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(BusyBeepingState, self).__init__(controller)
|
||||
self._controller.phone.play_busy_tone()
|
||||
|
||||
def leave(self):
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_timeout(self):
|
||||
return ForgottenState
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
class CallRunningState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
class WecktState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(WecktState, self).__init__(controller)
|
||||
self._controller.phone.play_ringback_tone()
|
||||
|
||||
def leave(self):
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
class ConnectingState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ringing(self):
|
||||
return WecktState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
def on_invalid_number(self):
|
||||
# TODO: play sound
|
||||
return BusyBeepingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
class DialingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(DialingState, self).__init__(controller)
|
||||
self._controller.phone.play_dial_tone()
|
||||
self.__dial_tone = True
|
||||
self.__number = ''
|
||||
|
||||
def leave(self):
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
self._controller.abort_timeout()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
self._controller.abort_timeout()
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
print('nummernschalter: %d' % (num))
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
self.__number += str(num)
|
||||
self._controller.abort_timeout()
|
||||
self._controller.set_timeout(self._controller.dialconfig.dial_timeout * 1000)
|
||||
self._controller.phone.read_text(str(num))
|
||||
|
||||
def on_timeout(self):
|
||||
number = self.__number
|
||||
print 'Dialing number:', number
|
||||
if number in self._controller.dialconfig.shortcuts:
|
||||
number = self._controller.dialconfig.shortcuts[number]
|
||||
print 'shortcut resolved:', number
|
||||
self._controller.phone.call(number)
|
||||
return ConnectingState
|
||||
|
||||
|
||||
class StateMachineController(object):
|
||||
def __init__(self, phone, feap, dialconfig):
|
||||
self.__phone = phone
|
||||
self.__feap = feap
|
||||
self.__dialconfig = dialconfig
|
||||
|
||||
self.__state = InitState(self)
|
||||
|
||||
self.__timeout = None
|
||||
|
||||
self.__running = True
|
||||
self.__evqueue = queue.Queue()
|
||||
self.__evthread = threading.Thread(target=self.__event_dispatcher)
|
||||
self.__evthread.start()
|
||||
|
||||
def __event_dispatcher(self):
|
||||
while self.__running:
|
||||
(evname, evargs, evkwargs) = self.__evqueue.get()
|
||||
if not evname:
|
||||
return
|
||||
|
||||
print('!!! event: %s' % (evname))
|
||||
handler = getattr(self.__state, 'on_%s' % (evname))
|
||||
try:
|
||||
newstate = handler(*evargs, **evkwargs)
|
||||
except IllegalEventError:
|
||||
print('illegal event occured!!!!!!!!!!!!!!!!!!!!', self.__state.__class__.__name__)
|
||||
if not newstate:
|
||||
continue
|
||||
|
||||
self.__state.leave()
|
||||
self.abort_timeout()
|
||||
|
||||
oldstate = self.__state.__class__
|
||||
print('%s -> %s' % (oldstate.__name__, newstate.__name__))
|
||||
self.__state = newstate(self)
|
||||
|
||||
def queue_event(self, evname, *evargs, **evkwargs):
|
||||
if not hasattr(AbstractState, 'on_%s' % (evname)):
|
||||
raise ValueError('Illegal event name: %s' % (evname))
|
||||
self.__evqueue.put((evname, evargs, evkwargs))
|
||||
|
||||
def set_timeout(self, timeout):
|
||||
self.__timeout = threading.Timer(timeout/1000, self.queue_event, args=['timeout'])
|
||||
self.__timeout.start()
|
||||
|
||||
def abort_timeout(self):
|
||||
if self.__timeout:
|
||||
self.__timeout.cancel()
|
||||
self.__timeout = None
|
||||
|
||||
@property
|
||||
def phone(self):
|
||||
return self.__phone
|
||||
|
||||
@property
|
||||
def feap(self):
|
||||
return self.__feap
|
||||
|
||||
@property
|
||||
def dialconfig(self):
|
||||
return self.__dialconfig
|
||||
|
||||
def stop(self, hard=False):
|
||||
if hard:
|
||||
self.__running = False
|
||||
self.__evqueue.put((None, None, None))
|
||||
|
||||
c = None
|
||||
def gabelschalter_cb(state):
|
||||
global c
|
||||
if state == 1:
|
||||
c.queue_event('gabelschalter_up')
|
||||
controller.queue_event('gabelschalter_up')
|
||||
else:
|
||||
c.queue_event('gabelschalter_down')
|
||||
controller.queue_event('gabelschalter_down')
|
||||
|
||||
def nummernschalter_active_cb():
|
||||
global c
|
||||
c.queue_event('nummernschalter_active')
|
||||
controller.queue_event('nummernschalter_active')
|
||||
|
||||
def nummernschalter_done_cb(digit):
|
||||
global c
|
||||
c.queue_event('nummernschalter_input', digit)
|
||||
controller.queue_event('nummernschalter_input', digit)
|
||||
|
||||
def phone_cb(event):
|
||||
if event == PhoneEvent.RegInProgress:
|
||||
c.queue_event('registration_in_progress')
|
||||
controller.queue_event('registration_in_progress')
|
||||
elif event == PhoneEvent.RegSuccessfull:
|
||||
c.queue_event('registration_successful')
|
||||
controller.queue_event('registration_successful')
|
||||
elif event == PhoneEvent.RegLost:
|
||||
c.queue_event('registration_lost')
|
||||
controller.queue_event('registration_lost')
|
||||
elif event == PhoneEvent.CallIncoming:
|
||||
c.queue_event('incoming_call')
|
||||
controller.queue_event('incoming_call')
|
||||
elif event == PhoneEvent.CallAccepted:
|
||||
c.queue_event('call_accepted')
|
||||
controller.queue_event('call_accepted')
|
||||
elif event == PhoneEvent.CallEnded:
|
||||
c.queue_event('call_ended')
|
||||
controller.queue_event('call_ended')
|
||||
elif event == PhoneEvent.CallRinging:
|
||||
c.queue_event('call_ringing')
|
||||
controller.queue_event('call_ringing')
|
||||
elif event == PhoneEvent.CallBusy:
|
||||
c.queue_event('call_ended')
|
||||
controller.queue_event('call_ended')
|
||||
elif event == PhoneEvent.CallInvalidNumber:
|
||||
c.queue_event('invalid_number')
|
||||
controller.queue_event('invalid_number')
|
||||
|
||||
if __name__ == '__main__':
|
||||
cfg = configreader.ConfigurationReader()
|
||||
|
@ -372,34 +45,13 @@ if __name__ == '__main__':
|
|||
|
||||
phone = PhoneInterface(cfg.phoneconfig)
|
||||
feap = FeApUserInterface(cfg.pinconfig)
|
||||
c = StateMachineController(phone, feap, cfg.dialconfig)
|
||||
|
||||
feap.add_gabelschalter_callback(gabelschalter_cb)
|
||||
feap.add_nummernschalter_active_callback(nummernschalter_active_cb)
|
||||
feap.add_nummernschalter_done_callback(nummernschalter_done_cb)
|
||||
phone.add_event_cb(phone_cb)
|
||||
controller = statemachine.StateMachineController(phone, feap, cfg.dialconfig)
|
||||
|
||||
phone.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
'''
|
||||
c.queue_event('gabelschalter_up')
|
||||
c.queue_event('nummernschalter_input', 4)
|
||||
c.queue_event('nummernschalter_input', 2)
|
||||
#c.queue_event('gabelschalter_down')
|
||||
#c.queue_event('call_accepted')
|
||||
c.queue_event('timeout')
|
||||
c.queue_event('call_ringing')
|
||||
#c.queue_event('gabelschalter_down')
|
||||
c.queue_event('call_accepted')
|
||||
c.queue_event('call_ended')
|
||||
c.queue_event('timeout')
|
||||
c.queue_event('gabelschalter_down')
|
||||
'''
|
||||
|
||||
except KeyboardInterrupt:
|
||||
phone.stop()
|
||||
feap.set_wecker(False)
|
||||
|
|
327
statemachine.py
Normal file
327
statemachine.py
Normal file
|
@ -0,0 +1,327 @@
|
|||
import threading
|
||||
import Queue as queue
|
||||
|
||||
class DialConfiguration(object):
|
||||
def __init__(self, dial_timeout, shortcuts, blacklist):
|
||||
self.dial_timeout = dial_timeout
|
||||
self.shortcuts = shortcuts
|
||||
self.blacklist = blacklist
|
||||
|
||||
class IllegalEventError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
An abstract state, needed to define all possible events.
|
||||
|
||||
"""
|
||||
class AbstractState(object):
|
||||
def on_registration_in_progress(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_registration_successful(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_registration_lost(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_incoming_call(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_ended(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_accepted(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_call_ringing(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_invalid_number(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
raise IllegalEventError()
|
||||
|
||||
def on_timeout(self):
|
||||
raise IllegalEventError()
|
||||
|
||||
def leave(self):
|
||||
return None
|
||||
|
||||
|
||||
"""
|
||||
The basic state that every other state inherits from. It defines default
|
||||
behaviour for some events (overriden if necessary).
|
||||
|
||||
"""
|
||||
class BaseState(AbstractState):
|
||||
def __init__(self, controller):
|
||||
self._controller = controller
|
||||
|
||||
def on_registration_lost(self):
|
||||
return InitState
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
return None
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return None
|
||||
|
||||
def on_incoming_call(self):
|
||||
self._controller.phone.decline_call()
|
||||
|
||||
def on_call_ended(self):
|
||||
# When an incoming call is declined, a call_ended event occurs, which
|
||||
# needs to be ignored, here.
|
||||
return None
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
return None
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
return None
|
||||
|
||||
|
||||
class InitState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(InitState, self).__init__(controller)
|
||||
self._controller.feap.set_schauzeichen(True)
|
||||
|
||||
def on_registration_in_progress(self):
|
||||
print('registration in progress')
|
||||
return RegisteringState
|
||||
|
||||
class RegisteringState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(RegisteringState, self).__init__(controller)
|
||||
|
||||
def on_registration_successful(self):
|
||||
print('registration successful')
|
||||
self._controller.feap.set_schauzeichen(False)
|
||||
return IdleState
|
||||
|
||||
class IdleState(BaseState):
|
||||
def on_incoming_call(self):
|
||||
print('incomfing call')
|
||||
caller = self._controller.phone.get_remote_number()
|
||||
print('From: %s' % caller)
|
||||
if caller in self._controller.dialconfig.blacklist:
|
||||
print('Caller on blacklist - declining')
|
||||
self._controller.phone.decline_call()
|
||||
return CallTerminatingState
|
||||
else:
|
||||
return SchelltState
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
print('gabel up')
|
||||
return DialingState
|
||||
|
||||
class SchelltState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(SchelltState, self).__init__(controller)
|
||||
self._controller.feap.set_wecker(True)
|
||||
|
||||
def leave(self):
|
||||
self._controller.feap.set_wecker(False)
|
||||
|
||||
def on_gabelschalter_up(self):
|
||||
return AcceptingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return IdleState
|
||||
|
||||
class AcceptingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(AcceptingState, self).__init__(controller)
|
||||
self._controller.phone.accept_call()
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
class CallTerminatingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(CallTerminatingState, self).__init__(controller)
|
||||
self._controller.phone.end_call()
|
||||
|
||||
def on_call_ended(self):
|
||||
return IdleState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return None
|
||||
|
||||
class ForgottenState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
class BusyBeepingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(BusyBeepingState, self).__init__(controller)
|
||||
self._controller.phone.play_busy_tone()
|
||||
|
||||
def leave(self):
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_timeout(self):
|
||||
return ForgottenState
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
class CallRunningState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
class WecktState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(WecktState, self).__init__(controller)
|
||||
self._controller.phone.play_ringback_tone()
|
||||
|
||||
def leave(self):
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
class ConnectingState(BaseState):
|
||||
def on_gabelschalter_down(self):
|
||||
return CallTerminatingState
|
||||
|
||||
def on_call_ringing(self):
|
||||
return WecktState
|
||||
|
||||
def on_call_accepted(self):
|
||||
return CallRunningState
|
||||
|
||||
def on_invalid_number(self):
|
||||
# TODO: play sound
|
||||
return BusyBeepingState
|
||||
|
||||
def on_call_ended(self):
|
||||
return BusyBeepingState
|
||||
|
||||
class DialingState(BaseState):
|
||||
def __init__(self, controller):
|
||||
super(DialingState, self).__init__(controller)
|
||||
self._controller.phone.play_dial_tone()
|
||||
self.__dial_tone = True
|
||||
self.__number = ''
|
||||
|
||||
def leave(self):
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
self._controller.abort_timeout()
|
||||
|
||||
def on_gabelschalter_down(self):
|
||||
return IdleState
|
||||
|
||||
def on_nummernschalter_active(self):
|
||||
self._controller.abort_timeout()
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
|
||||
def on_nummernschalter_input(self, num):
|
||||
print('nummernschalter: %d' % (num))
|
||||
if self.__dial_tone:
|
||||
self._controller.phone.stop_playing()
|
||||
self.__number += str(num)
|
||||
self._controller.abort_timeout()
|
||||
self._controller.set_timeout(self._controller.dialconfig.dial_timeout * 1000)
|
||||
self._controller.phone.read_text(str(num))
|
||||
|
||||
def on_timeout(self):
|
||||
number = self.__number
|
||||
print 'Dialing number:', number
|
||||
if number in self._controller.dialconfig.shortcuts:
|
||||
number = self._controller.dialconfig.shortcuts[number]
|
||||
print 'shortcut resolved:', number
|
||||
self._controller.phone.call(number)
|
||||
return ConnectingState
|
||||
|
||||
|
||||
class StateMachineController(object):
|
||||
def __init__(self, phone, feap, dialconfig):
|
||||
self.__phone = phone
|
||||
self.__feap = feap
|
||||
self.__dialconfig = dialconfig
|
||||
|
||||
self.__state = InitState(self)
|
||||
|
||||
self.__timeout = None
|
||||
|
||||
self.__running = True
|
||||
self.__evqueue = queue.Queue()
|
||||
self.__evthread = threading.Thread(target=self.__event_dispatcher)
|
||||
self.__evthread.start()
|
||||
|
||||
def __event_dispatcher(self):
|
||||
while self.__running:
|
||||
(evname, evargs, evkwargs) = self.__evqueue.get()
|
||||
if not evname:
|
||||
return
|
||||
|
||||
print('!!! event: %s' % (evname))
|
||||
handler = getattr(self.__state, 'on_%s' % (evname))
|
||||
try:
|
||||
newstate = handler(*evargs, **evkwargs)
|
||||
except IllegalEventError:
|
||||
print('illegal event occured!!!!!!!!!!!!!!!!!!!!', self.__state.__class__.__name__)
|
||||
if not newstate:
|
||||
continue
|
||||
|
||||
self.__state.leave()
|
||||
self.abort_timeout()
|
||||
|
||||
oldstate = self.__state.__class__
|
||||
print('%s -> %s' % (oldstate.__name__, newstate.__name__))
|
||||
self.__state = newstate(self)
|
||||
|
||||
def queue_event(self, evname, *evargs, **evkwargs):
|
||||
if not hasattr(AbstractState, 'on_%s' % (evname)):
|
||||
raise ValueError('Illegal event name: %s' % (evname))
|
||||
self.__evqueue.put((evname, evargs, evkwargs))
|
||||
|
||||
def set_timeout(self, timeout):
|
||||
self.__timeout = threading.Timer(timeout/1000, self.queue_event, args=['timeout'])
|
||||
self.__timeout.start()
|
||||
|
||||
def abort_timeout(self):
|
||||
if self.__timeout:
|
||||
self.__timeout.cancel()
|
||||
self.__timeout = None
|
||||
|
||||
@property
|
||||
def phone(self):
|
||||
return self.__phone
|
||||
|
||||
@property
|
||||
def feap(self):
|
||||
return self.__feap
|
||||
|
||||
@property
|
||||
def dialconfig(self):
|
||||
return self.__dialconfig
|
||||
|
||||
def stop(self, hard=False):
|
||||
if hard:
|
||||
self.__running = False
|
||||
self.__evqueue.put((None, None, None))
|
||||
|
Loading…
Reference in a new issue