more refactoring
[zanchey/dispense2.git] / sql-edition / servers / VendServer.py
index b623be6..c1ef276 100755 (executable)
@@ -11,11 +11,12 @@ if USE_DB: import pg
 from time import time, sleep
 from popen2 import popen2
 from LATClient import LATClient, LATClientException
 from time import time, sleep
 from popen2 import popen2
 from LATClient import LATClient, LATClientException
+from SerialClient import SerialClient, SerialClientException
 from VendingMachine import VendingMachine, VendingException
 from MessageKeeper import MessageKeeper
 from HorizScroll import HorizScroll
 from random import random, seed
 from VendingMachine import VendingMachine, VendingException
 from MessageKeeper import MessageKeeper
 from HorizScroll import HorizScroll
 from random import random, seed
-from Idler import TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler
+from Idler import TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
 import socket
 from posix import geteuid
 
 import socket
 from posix import geteuid
 
@@ -41,6 +42,7 @@ PIN_LENGTH = 4
 DOOR = 1
 SWITCH = 2
 KEY = 3
 DOOR = 1
 SWITCH = 2
 KEY = 3
+TICK = 4
 
 class DispenseDatabaseException(Exception): pass
 
 
 class DispenseDatabaseException(Exception): pass
 
@@ -146,6 +148,8 @@ def door_open_mode(v):
                e = v.next_event()
                if e == None: break
                (event, params) = e
                e = v.next_event()
                if e == None: break
                (event, params) = e
+               if event == TICK: break
+
                if event == DOOR:
                        if params == 1: # door closed
                                logging.warning('Leaving open door mode')
                if event == DOOR:
                        if params == 1: # door closed
                                logging.warning('Leaving open door mode')
@@ -189,21 +193,26 @@ idler = None
 def setup_idlers(v):
        global idlers, idler
        idlers = [
 def setup_idlers(v):
        global idlers, idler
        idlers = [
+                GrayIdler(v),
                StringIdler(v, text="Kill 'em all", repeat=False),
                StringIdler(v, text="Kill 'em all", repeat=False),
+                GrayIdler(v,one="*",zero="-"),
                StringIdler(v, text=CREDITS),
                StringIdler(v, text=CREDITS),
+                GrayIdler(v,one="/",zero="\\"),
+               ClockIdler(v),
+                GrayIdler(v,one="X",zero="O"),
+               FileIdler(v, '/usr/share/common-licenses/GPL-2'),
+                GrayIdler(v,one="*",zero="-",reorder=1),
                StringIdler(v, text=str(math.pi) + "            "),
                StringIdler(v, text=str(math.pi) + "            "),
+               ClockIdler(v),
+                GrayIdler(v,one="/",zero="\\",reorder=1),
                StringIdler(v, text=str(math.e) + "            "),
                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 - and order as Quinn - I am getting really hungry", repeat=False),
+               PipeIdler(v, "/usr/bin/ypcat", "passwd"),
                FortuneIdler(v),
                ClockIdler(v),
                StringIdler(v),
                FortuneIdler(v),
                ClockIdler(v),
                StringIdler(v),
-               GrayIdler(v),
                TrainIdler(v),
                TrainIdler(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),
                ]
     disabled = [
                ]
                ]
     disabled = [
                ]
@@ -232,21 +241,170 @@ def idle_step():
                choose_idler()
        idler.next()
 
                choose_idler()
        idler.next()
 
+class VendState:
+       def __init__(self,v):
+               self.mk = MessageKeeper(v)
+               self.cur_user = ''
+               self.cur_pin = ''
+               self.cur_selection = ''
+               self.time_to_autologout = None
+               self.time_to_idle = None
+               self.last_timeout_refresh = None
+
+
+def handle_door_event(event, params, v, vstatus):
+       if params == 0:
+               door_open_mode(v);
+               vstatus.cur_user = ''
+               vstatus.cur_pin = ''
+               vstatus.mk.set_message(GREETING)
+
+def handle_tick_event(event, params, v, vstatus):
+       # don't care right now.
+       pass
+
+def handle_switch_event(event, params, v, vstatus):
+       # don't care right now.
+       pass
+
+def handle_key_event(event, params, v, vstatus):
+       key = params
+       # complicated key handling here:
+       if len(vstatus.cur_user) < 5:
+               if key == 11:
+                       vstatus.cur_user = ''
+                       vstatus.mk.set_message(GREETING)
+                       return
+               vstatus.cur_user += chr(key + ord('0'))
+               vstatus.mk.set_message('UID: '+vstatus.cur_user)
+               if len(vstatus.cur_user) == 5:
+                       uid = int(vstatus.cur_user)
+                       if not has_good_pin(uid):
+                               logging.info('user '+vstatus.cur_user+' has a bad PIN')
+                               #mk.set_messages(
+                                       #[(center('INVALID'), False, 0.7),
+                                        #(center('PIN'), False, 0.7),
+                                        #(center('SETUP'), False, 1.0),
+                                        #(GREETING, False, None)])
+                               vstatus.mk.set_messages(
+                                       [(' '*10+'INVALID PIN SETUP'+' '*10, False, 3),
+                                        (GREETING, False, None)])
+                               vstatus.cur_user = ''
+                               vstatus.cur_pin = ''
+                               return
+                       vstatus.cur_pin = ''
+                       vstatus.mk.set_message('PIN: ')
+                       logging.info('need pin for user %s'%vstatus.cur_user)
+                       return
+       elif len(vstatus.cur_pin) < PIN_LENGTH:
+               if key == 11:
+                       if vstatus.cur_pin == '':
+                               vstatus.cur_user = ''
+                               vstatus.mk.set_message(GREETING)
+                               return
+                       vstatus.cur_pin = ''
+                       vstatus.mk.set_message('PIN: ')
+                       return
+               vstatus.cur_pin += chr(key + ord('0'))
+               vstatus.mk.set_message('PIN: '+'X'*len(vstatus.cur_pin))
+               if len(vstatus.cur_pin) == PIN_LENGTH:
+                       username = verify_user_pin(int(vstatus.cur_user), int(vstatus.cur_pin))
+                       if username:
+                               v.beep(0, False)
+                               vstatus.cur_selection = ''
+                               scroll_options(username, vstatus.mk, True)
+                               return
+                       else:
+                               v.beep(40, False)
+                               vstatus.mk.set_messages(
+                                       [(center('BAD PIN'), False, 1.0),
+                                        (center('SORRY'), False, 0.5),
+                                        (GREETING, False, None)])
+                               vstatus.cur_user = ''
+                               vstatus.cur_pin = ''
+                               return
+       elif len(vstatus.cur_selection) == 0:
+               if key == 11:
+                       vstatus.cur_pin = ''
+                       vstatus.cur_user = ''
+                       vstatus.cur_selection = ''
+                       vstatus.mk.set_messages(
+                               [(center('BYE!'), False, 1.5),
+                                (GREETING, False, None)])
+                       return
+               vstatus.cur_selection += chr(key + ord('0'))
+               vstatus.mk.set_message('SELECT: '+vstatus.cur_selection)
+               vstatus.time_to_autologout = None
+       elif len(vstatus.cur_selection) == 1:
+               if key == 11:
+                       vstatus.cur_selection = ''
+                       vstatus.time_to_autologout = None
+                       scroll_options(username, vstatus.mk)
+                       return
+               else:
+                       vstatus.cur_selection += chr(key + ord('0'))
+                       #make_selection(cur_selection)
+                       # XXX this should move somewhere else:
+                       if vstatus.cur_selection == '55':
+                               vstatus.mk.set_message('OPENSESAME')
+                               logging.info('dispensing a door for %s'%username)
+                               if geteuid() == 0:
+                                       ret = os.system('su - "%s" -c "dispense door"'%username)
+                               else:
+                                       ret = os.system('dispense door')
+                               if ret == 0:
+                                       logging.info('door opened')
+                                       vstatus.mk.set_message(center('DOOR OPEN'))
+                               else:
+                                       logging.warning('user %s tried to dispense a bad door'%username)
+                                       vstatus.mk.set_message(center('BAD DOOR'))
+                               sleep(1)
+                       elif vstatus.cur_selection == '91':
+                               cookie(v)
+                       elif vstatus.cur_selection == '99':
+                               scroll_options(username, vstatus.mk)
+                               vstatus.cur_selection = ''
+                               return
+                       elif vstatus.cur_selection[1] == '8':
+                               v.display('GOT COKE?')
+                               if ((os.system('su - "%s" -c "dispense %s"'%(username, vstatus.cur_selection[0])) >> 8) != 0):
+                                       v.display('SEEMS NOT')
+                               else:
+                                       v.display('GOT COKE!')
+                       else:
+                               v.display(vstatus.cur_selection+' - $1.00')
+                               if ((os.system('su - "%s" -c "dispense snack"'%(username)) >> 8) == 0):
+                                       v.vend(vstatus.cur_selection)
+                                       v.display('THANK YOU')
+                               else:
+                                       v.display('NO MONEY?')
+                       sleep(1)
+                       vstatus.cur_selection = ''
+                       vstatus.time_to_autologout = time() + 8
+                       vstatus.last_timeout_refresh = None
+
+
 def run_forever(rfh, wfh, options, cf):
        v = VendingMachine(rfh, wfh)
 def run_forever(rfh, wfh, options, cf):
        v = VendingMachine(rfh, wfh)
+       vstatus = VendState(v)
+
        logging.debug('PING is ' + str(v.ping()))
 
        if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword)
        logging.debug('PING is ' + str(v.ping()))
 
        if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword)
-       cur_user = ''
-       cur_pin = ''
-       cur_selection = ''
 
 
-       mk = MessageKeeper(v)
-       mk.set_message(GREETING)
-       time_to_autologout = None
+       vstatus.mk.set_message(GREETING)
        setup_idlers(v)
        setup_idlers(v)
-       time_to_idle = None
-       last_timeout_refresh = None
+
+
+       # This main loop is hideous and the work of the devil - mtearle
+       #
+       #
+       # notes for later surgery
+       #   (event, counter, ' ')
+       #        V
+       #   d[      ] = (method)
+       #
+       #  return state
 
        while True:
                if USE_DB:
 
        while True:
                if USE_DB:
@@ -255,170 +413,75 @@ def run_forever(rfh, wfh, options, cf):
                        except DispenseDatabaseException, e:
                                logging.error('Database error: '+str(e))
 
                        except DispenseDatabaseException, e:
                                logging.error('Database error: '+str(e))
 
-               if time_to_autologout != None:
-                       time_left = time_to_autologout - time()
-                       if time_left < 6 and (last_timeout_refresh is None or last_timeout_refresh > time_left):
-                               mk.set_message('LOGOUT: '+str(int(time_left)))
-                               last_timeout_refresh = int(time_left)
-                               cur_selection = ''
-
-               if time_to_autologout != None and time_to_autologout - time() <= 0:
-                       time_to_autologout = None
-                       cur_user = ''
-                       cur_pin = ''
-                       cur_selection = ''
-                       mk.set_message(GREETING)
-
-               if time_to_autologout and not mk.done(): time_to_autologout = None
-               if cur_user == '' and time_to_autologout: time_to_autologout = None
-               if len(cur_pin) == PIN_LENGTH and mk.done() and time_to_autologout == None:
+               if vstatus.time_to_autologout != None:
+                       time_left = vstatus.time_to_autologout - time()
+                       if time_left < 6 and (vstatus.last_timeout_refresh is None or vstatus.last_timeout_refresh > time_left):
+                               vstatus.mk.set_message('LOGOUT: '+str(int(time_left)))
+                               vstatus.last_timeout_refresh = int(time_left)
+                               vstatus.cur_selection = ''
+
+               if vstatus.time_to_autologout != None and vstatus.time_to_autologout - time() <= 0:
+                       vstatus.time_to_autologout = None
+                       vstatus.cur_user = ''
+                       vstatus.cur_pin = ''
+                       vstatus.cur_selection = ''
+                       vstatus.mk.set_message(GREETING)
+
+               if vstatus.time_to_autologout and not vstatus.mk.done(): 
+                       vstatus.time_to_autologout = None
+               if vstatus.cur_user == '' and vstatus.time_to_autologout: 
+                       vstatus.time_to_autologout = None
+               if len(vstatus.cur_pin) == PIN_LENGTH and vstatus.mk.done() and vstatus.time_to_autologout == None:
                        # start autologout
                        # start autologout
-                       time_to_autologout = time() + 15
+                       vstatus.time_to_autologout = time() + 15
+                       vstatus.last_timeout_refresh = None
 
 
-               if time_to_idle == None and cur_user == '':
-                       time_to_idle = time() + 5
+               if vstatus.time_to_idle == None and vstatus.cur_user == '':
+                       vstatus.time_to_idle = time() + 5
                        choose_idler()
                        choose_idler()
-               if time_to_idle is not None and cur_user != '': time_to_idle = None
-               if time_to_idle is not None and time() > time_to_idle: idle_step()
-               if time_to_idle is not None and time() > time_to_idle + 300:
-                       time_to_idle = time()
+               if vstatus.time_to_idle is not None and vstatus.cur_user != '': 
+                       vstatus.time_to_idle = None
+
+               if vstatus.time_to_idle is not None and time() > vstatus.time_to_idle: 
+                       idle_step()
+
+               if vstatus.time_to_idle is not None and time() > vstatus.time_to_idle + 30:
+                       vstatus.time_to_idle = time()
                        choose_idler()
 
                        choose_idler()
 
-               mk.update_display()
+               vstatus.mk.update_display()
 
                e = v.next_event(0)
 
                e = v.next_event(0)
-               if e == None:
+               (event, params) = e
+
+               if event == TICK:
                        e = v.next_event(0.05)
                        e = v.next_event(0.05)
-                       if e == None:
+                       (event, params) = e
+
+                       if event == TICK:
+                               handle_tick_event(event, params, v, vstatus)
                                continue
                                continue
-               time_to_idle = None
-               (event, params) = e
+               vstatus.time_to_idle = None
                logging.debug('Got event: ' + repr(e))
                logging.debug('Got event: ' + repr(e))
+
                if event == DOOR:
                if event == DOOR:
-                       if params == 0:
-                               door_open_mode(v);
-                               cur_user = ''
-                               cur_pin = ''
-                               mk.set_message(GREETING)
+                       handle_door_event(event, params, v, vstatus)
                elif event == SWITCH:
                elif event == SWITCH:
-                       # don't care right now.
-                       pass
+                       handle_switch_event(event, params, v, vstatus)
                elif event == KEY:
                elif event == KEY:
-                       key = params
-                       # complicated key handling here:
-                       if len(cur_user) < 5:
-                               if key == 11:
-                                       cur_user = ''
-                                       mk.set_message(GREETING)
-                                       continue
-                               cur_user += chr(key + ord('0'))
-                               mk.set_message('UID: '+cur_user)
-                               if len(cur_user) == 5:
-                                       uid = int(cur_user)
-                                       if not has_good_pin(uid):
-                                               logging.info('user '+cur_user+' has a bad PIN')
-                                               #mk.set_messages(
-                                                       #[(center('INVALID'), False, 0.7),
-                                                        #(center('PIN'), False, 0.7),
-                                                        #(center('SETUP'), False, 1.0),
-                                                        #(GREETING, False, None)])
-                                               mk.set_messages(
-                                                       [(' '*10+'INVALID PIN SETUP'+' '*10, False, 3),
-                                                        (GREETING, False, None)])
-                                               cur_user = ''
-                                               cur_pin = ''
-                                               continue
-                                       cur_pin = ''
-                                       mk.set_message('PIN: ')
-                                       logging.info('need pin for user %s'%cur_user)
-                                       continue
-                       elif len(cur_pin) < PIN_LENGTH:
-                               if key == 11:
-                                       if cur_pin == '':
-                                               cur_user = ''
-                                               mk.set_message(GREETING)
-                                               continue
-                                       cur_pin = ''
-                                       mk.set_message('PIN: ')
-                                       continue
-                               cur_pin += chr(key + ord('0'))
-                               mk.set_message('PIN: '+'X'*len(cur_pin))
-                               if len(cur_pin) == PIN_LENGTH:
-                                       username = verify_user_pin(int(cur_user), int(cur_pin))
-                                       if username:
-                                               v.beep(0, False)
-                                               cur_selection = ''
-                                               scroll_options(username, mk, True)
-                                               continue
-                                       else:
-                                               v.beep(40, False)
-                                               mk.set_messages(
-                                                       [(center('BAD PIN'), False, 1.0),
-                                                        (center('SORRY'), False, 0.5),
-                                                        (GREETING, False, None)])
-                                               cur_user = ''
-                                               cur_pin = ''
-                                               continue
-                       elif len(cur_selection) == 0:
-                               if key == 11:
-                                       cur_pin = ''
-                                       cur_user = ''
-                                       cur_selection = ''
-                                       mk.set_messages(
-                                               [(center('BYE!'), False, 1.5),
-                                                (GREETING, False, None)])
-                                       continue
-                               cur_selection += chr(key + ord('0'))
-                               mk.set_message('SELECT: '+cur_selection)
-                               time_to_autologout = None
-                       elif len(cur_selection) == 1:
-                               if key == 11:
-                                       cur_selection = ''
-                                       time_to_autologout = None
-                                       scroll_options(username, mk)
-                                       continue
-                               else:
-                                       cur_selection += chr(key + ord('0'))
-                                       #make_selection(cur_selection)
-                                       # XXX this should move somewhere else:
-                                       if cur_selection == '55':
-                                               mk.set_message('OPENSESAME')
-                                               logging.info('dispensing a door for %s'%username)
-                                               if geteuid() == 0:
-                                                       ret = os.system('su - "%s" -c "dispense door"'%username)
-                                               else:
-                                                       ret = os.system('dispense door')
-                                               if ret == 0:
-                                                       logging.info('door opened')
-                                                       mk.set_message(center('DOOR OPEN'))
-                                               else:
-                                                       logging.warning('user %s tried to dispense a bad door'%username)
-                                                       mk.set_message(center('BAD DOOR'))
-                                               sleep(1)
-                                       elif cur_selection == '91':
-                                               cookie(v)
-                                       elif cur_selection == '99':
-                                               scroll_options(username, mk)
-                                               cur_selection = ''
-                                               continue
-                                       elif cur_selection[1] == '8':
-                                               v.display('GOT COKE?')
-                                               os.system('su - "%s" -c "dispense %s"'%(username, cur_selection[0]))
-                                       else:
-                                               v.display('HERES A '+cur_selection)
-                                               v.vend(cur_selection)
-                                       sleep(0.5)
-                                       v.display('THANK YOU')
-                                       sleep(0.5)
-                                       cur_selection = ''
-                                       time_to_autologout = time() + 8
+                       handle_key_event(event, params, v, vstatus)
 
 def connect_to_vend(options, cf):
 
 def connect_to_vend(options, cf):
-       # Open vending machine via LAT?
+
        if options.use_lat:
                logging.info('Connecting to vending machine using LAT')
                latclient = LATClient(service = cf.ServiceName, password = cf.ServicePassword, server_name = cf.ServerName, connect_password = cf.ConnectPassword, priv_password = cf.PrivPassword)
                rfh, wfh = latclient.get_fh()
        if options.use_lat:
                logging.info('Connecting to vending machine using LAT')
                latclient = LATClient(service = cf.ServiceName, password = cf.ServicePassword, server_name = cf.ServerName, connect_password = cf.ConnectPassword, priv_password = cf.PrivPassword)
                rfh, wfh = latclient.get_fh()
+       elif options.use_serial:
+               # Open vending machine via serial.
+               logging.info('Connecting to vending machine using serial')
+               serialclient = SerialClient(port = '/dev/ttyS1', baud = 9600)
+               rfh,wfh = serialclient.get_fh()
        else:
                #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
                logging.info('Connecting to virtual vending machine on %s:%d'%(options.host,options.port))
        else:
                #(rfh, wfh) = popen2('../../virtualvend/vvend.py')
                logging.info('Connecting to virtual vending machine on %s:%d'%(options.host,options.port))
@@ -435,7 +498,9 @@ def parse_args():
 
        op = OptionParser(usage="%prog [OPTION]...")
        op.add_option('-f', '--config-file', default='/etc/dispense/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
 
        op = OptionParser(usage="%prog [OPTION]...")
        op.add_option('-f', '--config-file', default='/etc/dispense/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
-       op.add_option('--virtualvend', action='store_false', default=True, dest='use_lat', help='use the virtual vending server instead of LAT')
+       op.add_option('--serial', action='store_true', default=True, dest='use_serial', help='use the serial port')
+       op.add_option('--lat', action='store_true', default=False, dest='use_lat', help='use LAT')
+       op.add_option('--virtualvend', action='store_false', default=True, dest='use_serial', help='use the virtual vending server instead of LAT')
        op.add_option('-n', '--hostname', dest='host', default='localhost', help='the hostname to connect to for virtual vending machine mode (default: localhost)')
        op.add_option('-p', '--port', dest='port', default=5150, type='int', help='the port number to connect to (default: 5150)')
        op.add_option('-l', '--log-file', metavar='FILE', dest='log_file', default='', help='log output to the specified file')
        op.add_option('-n', '--hostname', dest='host', default='localhost', help='the hostname to connect to for virtual vending machine mode (default: localhost)')
        op.add_option('-p', '--port', dest='port', default=5150, type='int', help='the port number to connect to (default: 5150)')
        op.add_option('-l', '--log-file', metavar='FILE', dest='log_file', default='', help='log output to the specified file')
@@ -555,7 +620,7 @@ def do_vend_server(options, config_opts):
        while True:
                try:
                        rfh, wfh = connect_to_vend(options, config_opts)
        while True:
                try:
                        rfh, wfh = connect_to_vend(options, config_opts)
-               except (LATClientException, socket.error), e:
+               except (SerialClientException, socket.error), e:
                        (exc_type, exc_value, exc_traceback) = sys.exc_info()
                        del exc_traceback
                        logging.error("Connection error: "+str(exc_type)+" "+str(e))
                        (exc_type, exc_value, exc_traceback) = sys.exc_info()
                        del exc_traceback
                        logging.error("Connection error: "+str(exc_type)+" "+str(e))

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