Fix bug were cards read before logging in cannot be read until a logout occurs
[uccvend-vendserver.git] / VendServer / VendServer.py
index 2a9a55a..c16cff1 100755 (executable)
@@ -31,7 +31,11 @@ Nick Bannon
 Cameron Patrick
 and a collective of hungry alpacas.
 
+The MIFARE card reader bought to you by:
+David Adam
 
+Bug Hunting and hardware maintenance by:
+Mitchell Pomery
 
 For a good time call +61 8 6488 3901
 
@@ -252,28 +256,34 @@ idler = None
 def setup_idlers(v):
        global idlers, idler
        idlers = [
-                GrayIdler(v),
+               #
+               GrayIdler(v),
+               GrayIdler(v,one="*",zero="-"),
+               GrayIdler(v,one="/",zero="\\"),
+               GrayIdler(v,one="X",zero="O"),
+               GrayIdler(v,one="*",zero="-",reorder=1),
+               GrayIdler(v,one="/",zero="\\",reorder=1),
+               GrayIdler(v,one="X",zero="O",reorder=1),
+               #
+               ClockIdler(v),
+               ClockIdler(v),
+               ClockIdler(v),
+               #
+               StringIdler(v), # Hello Cruel World
                StringIdler(v, text="Kill 'em all", repeat=False),
-                GrayIdler(v,one="*",zero="-"),
                StringIdler(v, text=CREDITS),
-                GrayIdler(v,one="/",zero="\\"),
-               ClockIdler(v),
-                GrayIdler(v,one="X",zero="O"),
-               FileIdler(v, '/usr/share/common-licenses/GPL-2',affinity=2),
-                GrayIdler(v,one="*",zero="-",reorder=1),
                StringIdler(v, text=str(math.pi) + "            "),
-               ClockIdler(v),
-                GrayIdler(v,one="/",zero="\\",reorder=1),
                StringIdler(v, text=str(math.e) + "            "),
-                GrayIdler(v,one="X",zero="O",reorder=1),
-               StringIdler(v, text="    I want some pizza - please call Pizza Hut Shenton Park on +61 8 9381 9979 [now closed? - MSH] - and order as Quinn - I am getting really hungry", repeat=False),
-               PipeIdler(v, "/usr/bin/getent", "passwd"),
-               FortuneIdler(v),
-               ClockIdler(v),
-               StringIdler(v),
-               TrainIdler(v),
+               StringIdler(v, text="    I want some pizza - please call Broadway Pizza on +61 8 9389 8500 - and order as Quinn - I am getting really hungry", repeat=False),
                # "Hello World" in brainfuck
                StringIdler(v, text=">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++."),
+               #
+               TrainIdler(v),
+               #
+               FileIdler(v, '/usr/share/common-licenses/GPL-2',affinity=2),
+               #
+               PipeIdler(v, "/usr/bin/getent", "passwd"),
+               FortuneIdler(v,affinity=20),
                ]
        disabled = [
                ]
@@ -288,23 +298,33 @@ def reset_idler(v, vstatus, t = None):
 
 def choose_idler():
        global idlers, idler
-       iiindex = 0
-       average_affinity = 10 # guessing here...
-
-       if idler and idler.__class__ != GreetingIdler:
-               iiindex = idlers.index(idler)
-
-       iilen = len(idlers)
 
-       move = int(random()*len(idlers)*average_affinity) + 1
+       # Implementation of the King Of the Hill algorithm from;
+       # http://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/
+
+       #def weighted_choice_king(weights):
+       #       total = 0
+       #       winner = 0
+       #       for i, w in enumerate(weights):
+       #               total += w
+       #               if random.random() * total < w:
+       #                       winner = i
+       #       return winner
+       #       
+
+       total = 0
+       winner = None
+       
+       for choice in idlers:
+               weight = choice.affinity()
+               total += weight
+               if random() * total < weight:
+                       winner = choice
 
-       while move >= 0:
-               iiindex += 1
-               iiindex %= iilen
-               idler = idlers[iiindex]
-               move -= idler.affinity()
+       idler = winner
 
-       idler.reset()
+       if idler:
+               idler.reset()
 
 def idle_step(vstatus):
        global idler
@@ -370,6 +390,7 @@ def handle_getting_pin_idle(state, event, params, v, vstatus):
        pass
 
 def handle_get_selection_idle(state, event, params, v, vstatus):
+       global _last_card_id
        # don't care right now.
        ###
        ### State logging out ..
@@ -385,7 +406,7 @@ def handle_get_selection_idle(state, event, params, v, vstatus):
                vstatus.cur_user = ''
                vstatus.cur_pin = ''
                vstatus.cur_selection = ''
-                       
+               _last_card_id = -1
                reset_idler(v, vstatus)
 
        ### State fully logged out ... reset variables
@@ -407,13 +428,14 @@ def handle_get_selection_idle(state, event, params, v, vstatus):
 
 
 def handle_get_selection_key(state, event, params, v, vstatus):
+       global _last_card_id
        key = params
        if len(vstatus.cur_selection) == 0:
                if key == 11:
                        vstatus.cur_pin = ''
                        vstatus.cur_user = ''
                        vstatus.cur_selection = ''
-                       
+                       _last_card_id = -1
                        vstatus.mk.set_messages([(center('BYE!'), False, 1.5)])
                        reset_idler(v, vstatus, 2)
                        return
@@ -822,12 +844,17 @@ def handle_door_event(state, event, params, v, vstatus):
                logging.warning('Leaving open door mode')
                v.display("-YUM YUM!-")
 
+_last_card_id = -1
+
 def handle_mifare_event(state, event, params, v, vstatus):
+       global _last_card_id
        card_id = params
        # Translate card_id into uid.
-       if card_id == None:
+       if card_id == None or card_id == _last_card_id:
                return
 
+       _last_card_id = card_id
+       
        try:
                vstatus.cur_user = get_uid(card_id)
                logging.info('Mapped card id to uid %s'%vstatus.cur_user)
@@ -860,17 +887,21 @@ def handle_mifare_event(state, event, params, v, vstatus):
                         (center('SORRY'), False, 0.5)])
                vstatus.cur_user = ''
                vstatus.cur_pin = ''
+               _last_card_id = -1
        
                reset_idler(v, vstatus, 2)
                return
 
 def handle_mifare_add_user_event(state, event, params, v, vstatus):
-       card_id = params
+       global _last_card_id
+       card_id = params
 
        # Translate card_id into uid.
-       if card_id == None:
+       if card_id == None or card_id == _last_card_id:
                return
 
+       _last_card_id = card_id
+       
        try:
                if get_uid(card_id) != None:
                        vstatus.mk.set_messages(
@@ -910,24 +941,24 @@ def create_state_table(vstatus):
        vstatus.state_table[(STATE_DOOR_CLOSING,MIFARE,1)] = do_nothing
 
        vstatus.state_table[(STATE_GETTING_UID,TICK,1)] = handle_getting_uid_idle
-       vstatus.state_table[(STATE_GETTING_UID,DOOR,1)] = do_nothing
+       vstatus.state_table[(STATE_GETTING_UID,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_GETTING_UID,KEY,1)] = handle_getting_uid_key
        vstatus.state_table[(STATE_GETTING_UID,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_GETTING_PIN,TICK,1)] = handle_getting_pin_idle
-       vstatus.state_table[(STATE_GETTING_PIN,DOOR,1)] = do_nothing
+       vstatus.state_table[(STATE_GETTING_PIN,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_GETTING_PIN,KEY,1)] = handle_getting_pin_key
        vstatus.state_table[(STATE_GETTING_PIN,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_GET_SELECTION,TICK,1)] = handle_get_selection_idle
-       vstatus.state_table[(STATE_GET_SELECTION,DOOR,1)] = do_nothing
+       vstatus.state_table[(STATE_GET_SELECTION,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_GET_SELECTION,KEY,1)] = handle_get_selection_key
        vstatus.state_table[(STATE_GET_SELECTION,MIFARE,1)] = handle_mifare_add_user_event
 
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,1)] = handle_idle_grandfather_tick
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,2)] = handle_grandfather_tick
-       vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,1)] = do_nothing
-       vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = do_nothing
+       vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,1)] = handle_door_event
+       vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = handle_door_event
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,1)] = do_nothing
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,KEY,2)] = do_nothing
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,MIFARE,1)] = handle_mifare_event

UCC git Repository :: git.ucc.asn.au