You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
4.0 KiB
201 lines
4.0 KiB
10 years ago
|
#!/usr/bin/env python3
|
||
|
|
||
|
import threading
|
||
|
import queue
|
||
|
|
||
|
class IllegalEventError(Exception):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class AbstractState(object):
|
||
|
def __init__(self, controller):
|
||
|
pass
|
||
|
|
||
|
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_nummernschalter_input(self, num):
|
||
|
raise IllegalEventError()
|
||
|
|
||
|
def on_timeout(self):
|
||
|
raise IllegalEventError()
|
||
|
|
||
|
|
||
|
|
||
|
class IdleState(AbstractState):
|
||
|
def on_incoming_call(self):
|
||
|
print('incomfing call')
|
||
|
|
||
|
def on_gabelschalter_up(self):
|
||
|
print('gabel up')
|
||
|
return DailingState
|
||
|
|
||
|
def on_gabelschalter_down(self):
|
||
|
pass
|
||
|
|
||
|
def on_nummernschalter_input(self, x):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class SchelltState(AbstractState):
|
||
|
def on_gabelschalter_up(self):
|
||
|
return AcceptingState
|
||
|
|
||
|
def on_call_ended(self):
|
||
|
return IdleState
|
||
|
|
||
|
class AcceptingState(AbstractState):
|
||
|
def on_call_accepted(self):
|
||
|
return CallRunningState
|
||
|
|
||
|
class CallTerminatingState(AbstractState):
|
||
|
def on_call_ended(self):
|
||
|
return IdleState
|
||
|
|
||
|
def on_call_accepted(self):
|
||
|
return None
|
||
|
|
||
|
class ForgottenState(AbstractState):
|
||
|
def on_gabelschalter_down(self):
|
||
|
return IdleState
|
||
|
|
||
|
class BusyBeepingState(AbstractState):
|
||
|
def on_timeout(self):
|
||
|
return ForgottenState
|
||
|
|
||
|
def on_gabelschalter_down(self):
|
||
|
return IdleState
|
||
|
|
||
|
class CallRunningState(AbstractState):
|
||
|
def on_gabelschalter_down(self):
|
||
|
return CallTerminatingState
|
||
|
|
||
|
def on_call_ended(self):
|
||
|
return BusyBeepingState
|
||
|
|
||
|
class WecktState(AbstractState):
|
||
|
def on_gabelschalter_down(self):
|
||
|
return CallTerminatingState
|
||
|
|
||
|
def on_call_ended(self):
|
||
|
return BusyBeepingState
|
||
|
|
||
|
def on_call_accepted(self):
|
||
|
return CallRunningState
|
||
|
|
||
|
class ConnectingState(AbstractState):
|
||
|
def on_gabelschalter_down(self):
|
||
|
return CallTerminatingState
|
||
|
|
||
|
def on_call_ringing(self):
|
||
|
return WecktState
|
||
|
|
||
|
class DailingState(AbstractState):
|
||
|
def on_gabelschalter_down(self):
|
||
|
return IdleState
|
||
|
|
||
|
def on_nummernschalter_input(self, num):
|
||
|
print('nummernschalter: %d' % (num))
|
||
|
|
||
|
def on_timeout(self):
|
||
|
return ConnectingState
|
||
|
|
||
|
|
||
|
|
||
|
class TelefonapparatUserInterface(object):
|
||
|
def __init__(self):
|
||
|
pass
|
||
|
|
||
|
def add_gabelschalter_callback(self, cb):
|
||
|
pass
|
||
|
|
||
|
def add_nummernschalter_callback(self, cb):
|
||
|
pass
|
||
|
|
||
|
def set_wecker(self, enabled):
|
||
|
pass
|
||
|
|
||
|
def set_schauzeichen(self, enabled):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class StateMachineController(object):
|
||
|
def __init__(self):
|
||
|
self.__state = IdleState(self)
|
||
|
|
||
|
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!!!!!!!!!!!!!!!!!!!!')
|
||
|
if not newstate:
|
||
|
continue
|
||
|
|
||
|
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 stop(self, hard=False):
|
||
|
if hard:
|
||
|
self.__running = False
|
||
|
self.__evqueue.put((None, None, None))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
c = StateMachineController()
|
||
|
|
||
|
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')
|
||
|
|
||
|
c.stop()
|
||
|
|
||
|
|
||
|
|