Work from tonight:
[uccvend-vendserver.git] / sql-edition / servers / VendServer.py
index 0b45a40..fa5ba5b 100755 (executable)
@@ -43,17 +43,20 @@ DOOR = 1
 SWITCH = 2
 KEY = 3
 TICK = 4
+MIFARE = 5
 
 
-STATE_IDLE = 1
-STATE_DOOR_OPENING = 2
-STATE_DOOR_CLOSING = 3
-STATE_GETTING_UID = 4
-STATE_GETTING_PIN = 5
-STATE_GET_SELECTION = 6
-STATE_GRANDFATHER_CLOCK = 7
+(
+STATE_IDLE,
+STATE_DOOR_OPENING,
+STATE_DOOR_CLOSING,
+STATE_GETTING_UID,
+STATE_GETTING_PIN,
+STATE_GET_SELECTION,
+STATE_GRANDFATHER_CLOCK,
+) = range(1,8)
 
-TEXT_SPEED = 0.8
+TEXT_SPEED = 0.6
 IDLE_SPEED = 0.05
 
 class DispenseDatabaseException(Exception): pass
@@ -89,8 +92,14 @@ class DispenseDatabase:
 
 def scroll_options(username, mk, welcome = False):
        if welcome:
+           # Balance checking: crap code, [DAA]'s fault
+           acct = os.popen('dispense acct %s' % username)
+               balance = acct.read()[15:22]
+               acct.close()
+        
                msg = [(center('WELCOME'), False, TEXT_SPEED),
-                          (center(username), False, TEXT_SPEED)]
+                          (center(username), False, TEXT_SPEED),
+                          (center(balance), False, TEXT_SPEED),]
        else:
                msg = []
        choices = ' '*10+'CHOICES: '
@@ -155,8 +164,8 @@ def get_pin(uid):
 def has_good_pin(uid):
        return get_pin(uid) != None
 
-def verify_user_pin(uid, pin):
-       if get_pin(uid) == pin:
+def verify_user_pin(uid, pin, skip_pin_check=False):
+       if skip_pin_check or get_pin(uid) == pin:
                info = pwd.getpwuid(uid)
                logging.info('accepted pin for uid %d (%s)'%(uid,info.pw_name))
                return info.pw_name
@@ -375,10 +384,17 @@ def handle_get_selection_key(state, event, params, v, vstatus):
                        return
                else:
                        vstatus.cur_selection += chr(key + ord('0'))
-                       make_selection(v,vstatus)
-                       vstatus.cur_selection = ''
-                       vstatus.time_to_autologout = time() + 8
-                       vstatus.last_timeout_refresh = None
+                       if vstatus.cur_user:
+                               make_selection(v,vstatus)
+                               vstatus.cur_selection = ''
+                               vstatus.time_to_autologout = time() + 8
+                               vstatus.last_timeout_refresh = None
+                       else:
+                               # Price check mode.
+                               price_check(v,vstatus)
+                               vstatus.cur_selection = ''
+                               vstatus.time_to_autologout = None
+                               vstatus.last_timeout_refresh = None
 
 def make_selection(v, vstatus):
        # should use sudo here
@@ -396,7 +412,7 @@ def make_selection(v, vstatus):
                        logging.warning('user %s tried to dispense a bad door'%vstatus.username)
                        vstatus.mk.set_message(center('BAD DOOR'))
                sleep(1)
-       elif vstatus.cur_selection == '91':
+       elif vstatus.cur_selection == '81':
                cookie(v)
        elif vstatus.cur_selection == '99':
                scroll_options(vstatus.username, vstatus.mk)
@@ -416,18 +432,31 @@ def make_selection(v, vstatus):
                        price, shortname, name = get_snack( '--' )
                dollarprice = "$%.2f" % ( price / 100.0 )
                v.display(vstatus.cur_selection+' - %s'%dollarprice)
-               exitcode = os.system('su - "%s" -c "dispense give oday %d"'%(vstatus.username, price))
+               exitcode = os.system('su - "%s" -c "dispense give oday %d"'%(vstatus.username, price)) >> 8
                if (exitcode == 0):
                        # magic dispense syslog service
                        syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "vended %s (slot %s) for %s" % (name, vstatus.cur_selection, vstatus.username))
                        v.vend(vstatus.cur_selection)
                        v.display('THANK YOU')
                else:
-                       syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "failed vending %s (slot %s) for %s, code %d" % (name, vstatus.cur_selection, vstatus.username, exitcode))
+                       syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "failed vending %s (slot %s) for %s (code %d)" % (name, vstatus.cur_selection, vstatus.username, exitcode))
                        v.display('NO MONEY?')
        sleep(1)
 
 
+def price_check(v, vstatus):
+       if vstatus.cur_selection[1] == '8':
+               v.display(center('SEE COKE'))
+       else:
+               # first see if it's a named slot
+               try:
+                       price, shortname, name = get_snack( vstatus.cur_selection )
+               except:
+                       price, shortname, name = get_snack( '--' )
+               dollarprice = "$%.2f" % ( price / 100.0 )
+               v.display(vstatus.cur_selection+' - %s'%dollarprice)
+
+
 def handle_getting_pin_key(state, event, params, v, vstatus):
        #print "handle_getting_pin_key (s,e,p)", state, " ", event, " ", params
        key = params
@@ -467,19 +496,34 @@ def handle_getting_pin_key(state, event, params, v, vstatus):
 def handle_getting_uid_key(state, event, params, v, vstatus):
        #print "handle_getting_uid_key (s,e,p)", state, " ", event, " ", params
        key = params
+
        # complicated key handling here:
-       if len(vstatus.cur_user) < 5:
+
+       if len(vstatus.cur_user) == 0 and key == 9:
+               vstatus.cur_selection = ''
+               vstatus.time_to_autologout = None
+               vstatus.mk.set_message('PRICECHECK')
+               sleep(0.5)
+               scroll_options('', vstatus.mk)
+               vstatus.change_state(STATE_GET_SELECTION)
+               return
+
+       if len(vstatus.cur_user) <8:
                if key == 11:
                        vstatus.cur_user = ''
 
                        reset_idler(v, vstatus)
                        return
-
                vstatus.cur_user += chr(key + ord('0'))
-               vstatus.mk.set_message('UID: '+vstatus.cur_user)
-
+               #logging.info('dob: '+vstatus.cur_user)
+               if len(vstatus.cur_user) > 5:
+                       vstatus.mk.set_message('>'+vstatus.cur_user)
+               else:
+                       vstatus.mk.set_message('UID: '+vstatus.cur_user)
+       
        if len(vstatus.cur_user) == 5:
                uid = int(vstatus.cur_user)
+
                if uid == 0:
                        logging.info('user '+vstatus.cur_user+' has a bad PIN')
                        pfalken="""
@@ -675,24 +719,62 @@ def handle_grandfather_tick(state, event, params, v, vstatus):
                vstatus.change_state(STATE_IDLE,1)
 
 def handle_door_idle(state, event, params, v, vstatus):
+       def twiddle(clock,v,wise = 2):
+               if (clock % 4 == 0):
+                       v.display("-FEED  ME-")
+               elif (clock % 4 == 1+wise):
+                       v.display("\\FEED  ME/")
+               elif (clock % 4 == 2):
+                       v.display("-FEED  ME-")
+               elif (clock % 4 == 3-wise):
+                       v.display("/FEED  ME\\")
+
        # don't care right now.
-       pass
+       now = int(time())
+
+       if ((now % 60 % 2) == 0):
+               twiddle(now, v)
+       else:
+               twiddle(now, v, wise=0)
+
 
 def handle_door_event(state, event, params, v, vstatus):
-       if params == 1:  #door open
+       if params == 0:  #door open
                vstatus.change_state(STATE_DOOR_OPENING)
                logging.warning("Entering open door mode")
                v.display("-FEED  ME-")
                #door_open_mode(v);
                vstatus.cur_user = ''
                vstatus.cur_pin = ''
-       elif params == 0:  #door closed
+       elif params == 1:  #door closed
                vstatus.change_state(STATE_DOOR_CLOSING)
                reset_idler(v, vstatus, 3)
 
                logging.warning('Leaving open door mode')
                v.display("-YUM YUM!-")
 
+def handle_mifare_event(state, event, params, v, vstatus):
+       card_uid = params
+       # Translate card_id into uid.
+       vstatus.cur_user = str(card_uid)
+       vstatus.username = verify_user_pin(int(card_uid), None, True)
+       if vstatus.username:
+               v.beep(0, False)
+               vstatus.cur_selection = ''
+               vstatus.change_state(STATE_GET_SELECTION)
+               scroll_options(vstatus.username, vstatus.mk, True)
+               return
+       else:
+               v.beep(40, False)
+               vstatus.mk.set_messages(
+                       [(center('BAD CARD'), False, 1.0),
+                        (center('SORRY'), False, 0.5)])
+               vstatus.cur_user = ''
+               vstatus.cur_pin = ''
+       
+               reset_idler(v, vstatus, 2)
+               return
+
 def return_to_idle(state,event,params,v,vstatus):
        reset_idler(v, vstatus)
 
@@ -700,26 +782,32 @@ def create_state_table(vstatus):
        vstatus.state_table[(STATE_IDLE,TICK,1)] = handle_idle_tick
        vstatus.state_table[(STATE_IDLE,KEY,1)] = handle_idle_key
        vstatus.state_table[(STATE_IDLE,DOOR,1)] = handle_door_event
+       vstatus.state_table[(STATE_IDLE,MIFARE,1)] = handle_mifare_event
 
        vstatus.state_table[(STATE_DOOR_OPENING,TICK,1)] = handle_door_idle
        vstatus.state_table[(STATE_DOOR_OPENING,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_DOOR_OPENING,KEY,1)] = do_nothing
+       vstatus.state_table[(STATE_DOOR_OPENING,MIFARE,1)] = do_nothing
 
        vstatus.state_table[(STATE_DOOR_CLOSING,TICK,1)] = return_to_idle
        vstatus.state_table[(STATE_DOOR_CLOSING,DOOR,1)] = handle_door_event
        vstatus.state_table[(STATE_DOOR_CLOSING,KEY,1)] = do_nothing
+       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,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,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,KEY,1)] = handle_get_selection_key
+       vstatus.state_table[(STATE_GET_SELECTION,MIFARE,1)] = do_nothing
 
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,1)] = handle_idle_grandfather_tick
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,TICK,2)] = handle_grandfather_tick
@@ -727,6 +815,7 @@ def create_state_table(vstatus):
        vstatus.state_table[(STATE_GRANDFATHER_CLOCK,DOOR,2)] = do_nothing
        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
 
 def get_state_table_handler(vstatus, state, event, counter):
        return vstatus.state_table[(state,event,counter)]
@@ -769,7 +858,6 @@ def run_forever(rfh, wfh, options, cf):
                        except DispenseDatabaseException, e:
                                logging.error('Database error: '+str(e))
 
-
                timeout = time_to_next_update(vstatus)
                e = v.next_event(timeout)
                (event, params) = e

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