# vim:ts=4
USE_DB = 0
+USE_MIFARE = 1
import ConfigParser
-import sys, os, string, re, pwd, signal, math
+import sys, os, string, re, pwd, signal, math, syslog
import logging, logging.handlers
from traceback import format_tb
if USE_DB: import pg
-from time import time, sleep
-from popen2 import popen2
+from time import time, sleep, mktime, localtime
+from subprocess import Popen, PIPE
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 Idler import TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
+from Idler import GreetingIdler,TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
+from SnackConfig import get_snack#, get_snacks
import socket
from posix import geteuid
+from LDAPConnector import get_uid, set_card_id
CREDITS="""
This vending machine software brought to you by:
"""
-GREETING = 'UCC SNACKS'
PIN_LENGTH = 4
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_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
+IDLE_SPEED = 0.05
class DispenseDatabaseException(Exception): pass
def scroll_options(username, mk, welcome = False):
if welcome:
- msg = [(center('WELCOME'), False, 0.8),
- (center(username), False, 0.8)]
+ # Balance checking
+ acct, unused = Popen(['dispense', 'acct', username], close_fds=True, stdout=PIPE).communicate()
+ # this is fucking appalling
+ balance = acct[acct.find("$")+1:acct.find("(")].strip()
+
+ msg = [(center('WELCOME'), False, TEXT_SPEED),
+ (center(username), False, TEXT_SPEED),
+ (center(balance), False, TEXT_SPEED),]
else:
msg = []
choices = ' '*10+'CHOICES: '
- try:
- coke_machine = file('/home/other/coke/coke_contents')
- cokes = coke_machine.readlines()
- coke_machine.close()
- except:
- cokes = []
- pass
+
+ # Get coke contents
+ cokes = []
+ for i in range(0, 7):
+ args = ('dispense', 'iteminfo', 'coke:%i' % i)
+ info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
+ m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info)
+ cents = int(m.group(1))*100 + int(m.group(2))
+ cokes.append('%i %i %s' % (i, cents, m.group(3)));
+
for c in cokes:
c = c.strip()
(slot_num, price, slot_name) = c.split(' ', 2)
if slot_name == 'dead': continue
- choices += '%s8-%s (%sc) '%(slot_num, slot_name, price)
+ choices += '%s-(%sc)-%s8 '%(slot_name, price, slot_num)
+
+# we don't want to print snacks for now since it'll be too large
+# and there's physical bits of paper in the machine anyway - matt
+# try:
+# snacks = get_snacks()
+# except:
+# snacks = {}
+#
+# for slot, ( name, price ) in snacks.items():
+# choices += '%s8-%s (%sc) ' % ( slot, name, price )
+
choices += '55-DOOR '
- choices += 'OR A SNACK. '
+ choices += 'OR ANOTHER SNACK. '
choices += '99 TO READ AGAIN. '
choices += 'CHOICE? '
msg.append((choices, False, None))
logging.info('getting pin for uid %d: .pin not found in home directory'%uid)
return None
if s.st_mode & 077:
- logging.info('getting pin for uid %d: .pin has wrong permissions'%uid)
- return None
+ logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%uid)
+ os.chmod(pinfile, 0600)
try:
f = file(pinfile)
except IOError:
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))
+ if skip_pin_check:
+ logging.info('accepted mifare for uid %d (%s)'%(uid,info.pw_name))
+ else:
+ logging.info('accepted pin for uid %d (%s)'%(uid,info.pw_name))
return info.pw_name
else:
logging.info('refused pin for uid %d'%(uid))
GrayIdler(v,one="/",zero="\\"),
ClockIdler(v),
GrayIdler(v,one="X",zero="O"),
- FileIdler(v, '/usr/share/common-licenses/GPL-2'),
+ 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 - and order as Quinn - I am getting really hungry", repeat=False),
- PipeIdler(v, "/usr/bin/ypcat", "passwd"),
+ 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),
]
disabled = [
]
- idler = choose_idler()
+
+def reset_idler(v, vstatus, t = None):
+ global idlers, idler
+ idler = GreetingIdler(v, t)
+ vstatus.time_of_next_idlestep = time()+idler.next()
+ vstatus.time_of_next_idler = None
+ vstatus.time_to_autologout = None
+ vstatus.change_state(STATE_IDLE, 1)
def choose_idler():
global idlers, idler
iiindex = 0
+ average_affinity = 10 # guessing here...
- if idler:
+ if idler and idler.__class__ != GreetingIdler:
iiindex = idlers.index(idler)
iilen = len(idlers)
- move = int(random()*len(idlers)) + 1
+ move = int(random()*len(idlers)*average_affinity) + 1
while move >= 0:
- idler = idlers[( (iiindex + 1) % iilen)]
- move = move - idler.affinity()
+ iiindex += 1
+ iiindex %= iilen
+ idler = idlers[iiindex]
+ move -= idler.affinity()
idler.reset()
-def idle_step():
+def idle_step(vstatus):
global idler
if idler.finished():
choose_idler()
- idler.next()
+ vstatus.time_of_next_idler = time() + 30
+ nextidle = idler.next()
+ if nextidle is None:
+ nextidle = IDLE_SPEED
+ vstatus.time_of_next_idlestep = time()+nextidle
class VendState:
def __init__(self,v):
self.cur_selection = ''
self.time_to_autologout = None
- self.time_to_idle = None
-
self.last_timeout_refresh = None
+ def change_state(self,newstate,newcounter=None):
+ if self.state != newstate:
+ #print "Changing state from: ",
+ #print self.state,
+ #print " to ",
+ #print newstate
+ self.state = newstate
+
+ if newcounter is not None and self.counter != newcounter:
+ #print "Changing counter from: ",
+ #print self.counter,
+ #print " to ",
+ #print newcounter
+ self.counter = newcounter
+
def handle_tick_event(event, params, v, vstatus):
vstatus.cur_pin = ''
vstatus.cur_selection = ''
- idle_in(vstatus,2)
- vstatus.state = STATE_IDLE
-
- vstatus.mk.set_message(GREETING)
+ reset_idler(v, vstatus)
### State fully logged out ... reset variables
if vstatus.time_to_autologout and not vstatus.mk.done():
vstatus.time_to_autologout = time() + 15
vstatus.last_timeout_refresh = None
- ### State logged out ... after normal logout??
- # perhaps when logged in?
- if vstatus.time_to_idle is not None and vstatus.cur_user != '':
- vstatus.time_to_idle = None
-
-
## FIXME - this may need to be elsewhere.....
# need to check
vstatus.mk.update_display()
vstatus.cur_user = ''
vstatus.cur_selection = ''
- idle_in(vstatus,2)
- vstatus.state = STATE_IDLE
-
- vstatus.mk.set_messages(
- [(center('BYE!'), False, 1.5),
- (GREETING, False, None)])
+ vstatus.mk.set_messages([(center('BYE!'), False, 1.5)])
+ reset_idler(v, vstatus, 2)
return
vstatus.cur_selection += chr(key + ord('0'))
vstatus.mk.set_message('SELECT: '+vstatus.cur_selection)
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
vstatus.mk.set_message('OPENSESAME')
logging.info('dispensing a door for %s'%vstatus.username)
if geteuid() == 0:
- ret = os.system('su - "%s" -c "dispense door"'%vstatus.username)
+ #ret = os.system('su - "%s" -c "dispense door"'%vstatus.username)
+ ret = os.system('dispense -u "%s" door'%vstatus.username)
else:
ret = os.system('dispense door')
if ret == 0:
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)
vstatus.cur_selection = ''
return
elif vstatus.cur_selection[1] == '8':
- v.display('GOT COKE?')
- if ((os.system('su - "%s" -c "dispense %s"'%(vstatus.username, vstatus.cur_selection[0])) >> 8) != 0):
+ v.display('GOT DRINK?')
+ if ((os.system('dispense -u "%s" coke:%s'%(vstatus.username, vstatus.cur_selection[0])) >> 8) != 0):
v.display('SEEMS NOT')
else:
- v.display('GOT COKE!')
+ v.display('GOT DRINK!')
else:
- v.display(vstatus.cur_selection+' - $1.00')
- if ((os.system('su - "%s" -c "dispense snack"'%(vstatus.username)) >> 8) == 0):
+ # 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)
+ exitcode = os.system('dispense -u "%s" give \>snacksales %d "%s"'%(vstatus.username, price, name)) >> 8
+# exitcode = os.system('dispense -u "%s" give \>sales\:snack %d "%s"'%(vstatus.username, price, name)) >> 8
+# exitcode = os.system('dispense -u "%s" snack:%s'%(vstatus.username, vstatus.cur_selection)) >> 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:
+ elif (exitcode == 5): # RV_BALANCE
v.display('NO MONEY?')
+ elif (exitcode == 4): # RV_ARGUMENTS (zero give causes arguments)
+ v.display('EMPTY SLOT')
+ elif (exitcode == 1): # RV_BADITEM (Dead slot)
+ v.display('EMPTY SLOT')
+ 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))
+ v.display('UNK ERROR')
sleep(1)
+def price_check(v, vstatus):
+ if vstatus.cur_selection[1] == '8':
+ args = ('dispense', 'iteminfo', 'coke:' + vstatus.cur_selection[0])
+ info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
+ dollarprice = re.match("\s*[a-z]+:\d+\s+(\d+\.\d\d)\s+([^\n]+)", info).group(1)
+ 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
if key == 11:
if vstatus.cur_pin == '':
vstatus.cur_user = ''
- vstatus.mk.set_message(GREETING)
-
- idle_in(vstatus,5)
- vstatus.state = STATE_IDLE
+ reset_idler(v, vstatus)
return
vstatus.cur_pin = ''
if vstatus.username:
v.beep(0, False)
vstatus.cur_selection = ''
- vstatus.state = STATE_GET_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 PIN'), False, 1.0),
- (center('SORRY'), False, 0.5),
- (GREETING, False, None)])
+ (center('SORRY'), False, 0.5)])
vstatus.cur_user = ''
vstatus.cur_pin = ''
- idle_in(vstatus,5)
- vstatus.state = STATE_IDLE
+ reset_idler(v, vstatus, 2)
return
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 = ''
- vstatus.mk.set_message(GREETING)
- idle_in(vstatus,5)
- vstatus.state = STATE_IDLE
+ 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="""
+CARRIER DETECTED
+
+CONNECT 128000
+
+Welcome to Picklevision Sytems, Sunnyvale, CA
+
+Greetings Professor Falken.
+
+
+
+
+Shall we play a game?
+
+
+Please choose from the following menu:
+
+1. Tic-Tac-Toe
+2. Chess
+3. Checkers
+4. Backgammon
+5. Poker
+6. Toxic and Biochemical Warfare
+7. Global Thermonuclear War
+
+7 [ENTER]
+
+Wouldn't you prefer a nice game of chess?
+
+""".replace('\n',' ')
+ vstatus.mk.set_messages([(pfalken, False, 10)])
+ vstatus.cur_user = ''
+ vstatus.cur_pin = ''
+
+ reset_idler(v, vstatus, 10)
+
+ return
+
if not has_good_pin(uid):
logging.info('user '+vstatus.cur_user+' has a bad PIN')
vstatus.mk.set_messages(
- [(' '*10+'INVALID PIN SETUP'+' '*10, False, 3),
- (GREETING, False, None)])
+ [(' '*10+'INVALID PIN SETUP'+' '*11, False, 3)])
vstatus.cur_user = ''
vstatus.cur_pin = ''
- idle_in(vstatus,5)
- vstatus.state = STATE_IDLE
+ reset_idler(v, vstatus, 3)
return
vstatus.cur_pin = ''
vstatus.mk.set_message('PIN: ')
logging.info('need pin for user %s'%vstatus.cur_user)
- vstatus.state = STATE_GETTING_PIN
+ vstatus.change_state(STATE_GETTING_PIN)
return
if key == 11:
vstatus.cur_user = ''
- vstatus.mk.set_message(GREETING)
- idle_in(vstatus,5)
- choose_idler()
+ reset_idler(v, vstatus)
return
- vstatus.state = STATE_GETTING_UID
+ vstatus.change_state(STATE_GETTING_UID)
run_handler(event, key, v, vstatus)
def handle_idle_tick(state, event, params, v, vstatus):
- ### State logged out ... initiate idler in 5 (first start?)
- if vstatus.time_to_idle == None and vstatus.cur_user == '':
- vstatus.time_to_idle = time() + 5
- choose_idler()
-
### State idling
+ if vstatus.mk.done():
+ idle_step(vstatus)
- 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()
+ if vstatus.time_of_next_idler and time() > vstatus.time_of_next_idler:
+ vstatus.time_of_next_idler = time() + 30
choose_idler()
###
vstatus.mk.update_display()
+ vstatus.change_state(STATE_GRANDFATHER_CLOCK)
+ run_handler(event, params, v, vstatus)
+ sleep(0.05)
+
+def beep_on(when, before=0):
+ start = int(when - before)
+ end = int(when)
+ now = int(time())
+
+ if now >= start and now <= end:
+ return 1
+ return 0
+
+def handle_idle_grandfather_tick(state, event, params, v, vstatus):
+ ### check for interesting times
+ now = localtime()
+
+ quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]])
+ halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]])
+ threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]])
+ fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]])
+
+ hourfromnow = localtime(time() + 3600)
+
+ #onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]])
+ onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \
+ 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]])
+
+ ## check for X seconds to the hour
+ ## if case, update counter to 2
+ if beep_on(onthehour,15) \
+ or beep_on(halfhour,0) \
+ or beep_on(quarterhour,0) \
+ or beep_on(threequarterhour,0) \
+ or beep_on(fivetothehour,0):
+ vstatus.change_state(STATE_GRANDFATHER_CLOCK,2)
+ run_handler(event, params, v, vstatus)
+ else:
+ vstatus.change_state(STATE_IDLE)
+
+def handle_grandfather_tick(state, event, params, v, vstatus):
+ go_idle = 1
+
+ msg = []
+ ### we live in interesting times
+ now = localtime()
+
+ quarterhour = mktime([now[0],now[1],now[2],now[3],15,0,now[6],now[7],now[8]])
+ halfhour = mktime([now[0],now[1],now[2],now[3],30,0,now[6],now[7],now[8]])
+ threequarterhour = mktime([now[0],now[1],now[2],now[3],45,0,now[6],now[7],now[8]])
+ fivetothehour = mktime([now[0],now[1],now[2],now[3],55,0,now[6],now[7],now[8]])
+
+ hourfromnow = localtime(time() + 3600)
+
+# onthehour = mktime([now[0],now[1],now[2],now[3],03,0,now[6],now[7],now[8]])
+ onthehour = mktime([hourfromnow[0],hourfromnow[1],hourfromnow[2],hourfromnow[3], \
+ 0,0,hourfromnow[6],hourfromnow[7],hourfromnow[8]])
+
+
+ #print "when it fashionable to wear a onion on your hip"
+
+ if beep_on(onthehour,15):
+ go_idle = 0
+ next_hour=((hourfromnow[3] + 11) % 12) + 1
+ if onthehour - time() < next_hour and onthehour - time() > 0:
+ v.beep(0, False)
+
+ t = int(time())
+ if (t % 2) == 0:
+ msg.append(("DING!", False, None))
+ else:
+ msg.append((" DING!", False, None))
+ elif int(onthehour - time()) == 0:
+ v.beep(255, False)
+ msg.append((" BONG!", False, None))
+ msg.append((" IT'S "+ str(next_hour) + "O'CLOCK AND ALL IS WELL .....", False, TEXT_SPEED*4))
+ elif beep_on(halfhour,0):
+ go_idle = 0
+ v.beep(0, False)
+ msg.append((" HALFHOUR ", False, 50))
+ elif beep_on(quarterhour,0):
+ go_idle = 0
+ v.beep(0, False)
+ msg.append((" QTR HOUR ", False, 50))
+ elif beep_on(threequarterhour,0):
+ go_idle = 0
+ v.beep(0, False)
+ msg.append((" 3 QTR HR ", False, 50))
+ elif beep_on(fivetothehour,0):
+ go_idle = 0
+ v.beep(0, False)
+ msg.append(("Quick run to your lectures! Hurry! Hurry!", False, TEXT_SPEED*4))
+ else:
+ go_idle = 1
+
+ ## check for X seconds to the hour
+
+ if len(msg):
+ vstatus.mk.set_messages(msg)
+ sleep(1)
+
+ vstatus.mk.update_display()
+ ## if no longer case, return to idle
+
+ ## change idler to be clock
+ if go_idle and vstatus.mk.done():
+ 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):
- vstatus.time_to_idle = None
- if params == 1: #door open
- vstatus.state = STATE_DOOR_OPENING
+def handle_door_event(state, event, params, v, vstatus):
+ 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
- vstatus.state = STATE_DOOR_CLOSING
- idle_in(vstatus, 5)
+ 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 idle_in(vstatus,seconds):
- vstatus.time_to_idle = time() + seconds
+def handle_mifare_event(state, event, params, v, vstatus):
+ card_id = params
+ # Translate card_id into uid.
+ if card_id == None:
+ return
-def return_to_idle(state,event,params,v,vstatus):
- if vstatus.time_to_idle is not None and time() > vstatus.time_to_idle:
- vstatus.mk.set_message(GREETING)
- vstatus.state = STATE_IDLE
+ try:
+ vstatus.cur_user = get_uid(card_id)
+ logging.info('Mapped card id to uid %s'%vstatus.cur_user)
+ vstatus.username = verify_user_pin(int(vstatus.cur_user), None, True)
+ except ValueError:
+ vstatus.username = None
+ 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
- if not vstatus.time_to_idle:
- vstatus.mk.set_message(GREETING)
- vstatus.state = STATE_IDLE
+
+def handle_mifare_add_user_event(state, event, params, v, vstatus):
+ card_id = params
+
+ # Translate card_id into uid.
+ if card_id == None:
return
+ try:
+ if get_uid(card_id) != None:
+ vstatus.mk.set_messages(
+ [(center('ALREADY'), False, 0.5),
+ (center('ENROLLED'), False, 0.5)])
+
+ # scroll_options(vstatus.username, vstatus.mk)
+ return
+ except ValueError:
+ pass
+
+ logging.info('Enrolling card %s to uid %s (%s)'%(card_id, vstatus.cur_user, vstatus.username))
+ set_card_id(vstatus.cur_user, card_id)
+ vstatus.mk.set_messages(
+ [(center('CARD'), False, 0.5),
+ (center('ENROLLED'), False, 0.5)])
+
+ # scroll_options(vstatus.username, vstatus.mk)
+
+def return_to_idle(state,event,params,v,vstatus):
+ reset_idler(v, vstatus)
+
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)] = 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,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)]
+def time_to_next_update(vstatus):
+ idle_update = vstatus.time_of_next_idlestep - time()
+ if not vstatus.mk.done() and vstatus.mk.next_update is not None:
+ mk_update = vstatus.mk.next_update - time()
+ if mk_update < idle_update:
+ idle_update = mk_update
+ return idle_update
+
def run_forever(rfh, wfh, options, cf):
- v = VendingMachine(rfh, wfh)
+ v = VendingMachine(rfh, wfh, USE_MIFARE)
vstatus = VendState(v)
create_state_table(vstatus)
if USE_DB: db = DispenseDatabase(v, cf.DBServer, cf.DBName, cf.DBUser, cf.DBPassword)
- vstatus.mk.set_message(GREETING)
setup_idlers(v)
- choose_idler()
- vstatus.mk.set_message("Booted")
-
+ reset_idler(v, vstatus)
# This main loop was hideous and the work of the devil.
# This has now been fixed (mostly) - mtearle
except DispenseDatabaseException, e:
logging.error('Database error: '+str(e))
-
- e = v.next_event(0)
+ timeout = time_to_next_update(vstatus)
+ e = v.next_event(timeout)
(event, params) = e
- vstatus.counter=1
run_handler(event, params, v, vstatus)
# logging.debug('Got event: ' + repr(e))
sock.connect((options.host, options.port))
rfh = sock.makefile('r')
wfh = sock.makefile('w')
+ global USE_MIFARE
+ USE_MIFARE = 0
return rfh, wfh
from optparse import OptionParser
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('-f', '--config-file', default='/etc/dispense2/servers.conf', metavar='FILE', dest='config_file', help='use the specified config file instead of /etc/dispense/servers.conf')
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')
sleep(5)
continue
+# run_forever(rfh, wfh, options, config_opts)
+
try:
run_forever(rfh, wfh, options, config_opts)
except VendingException: