idlers = []
idler = None
+config_options = {
+ 'DBServer': ('Database', 'Server'),
+ 'DBName': ('Database', 'Name'),
+ 'DBUser': ('VendingMachine', 'DBUser'),
+ 'DBPassword': ('VendingMachine', 'DBPassword'),
+
+ 'ServiceName': ('VendingMachine', 'ServiceName'),
+ 'ServicePassword': ('VendingMachine', 'Password'),
+
+ 'ServerName': ('DecServer', 'Name'),
+ 'ConnectPassword': ('DecServer', 'ConnectPassword'),
+ 'PrivPassword': ('DecServer', 'PrivPassword'),
+ }
+
+class VendConfigFile:
+ def __init__(self, config_file, options):
+ try:
+ cp = ConfigParser.ConfigParser()
+ cp.read(config_file)
+
+ for option in options:
+ section, name = options[option]
+ value = cp.get(section, name)
+ self.__dict__[option] = value
+
+ except ConfigParser.Error, e:
+ raise SystemExit("Error reading config file "+config_file+": " + str(e))
class DispenseDatabaseException(Exception): pass
while notifier is not None:
self.process_requests()
notify = self.db.getnotify()
-
+"""
+This class manages the current state of the vending machine.
+"""
class VendState:
def __init__(self,v):
self.state_table = {}
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
-
-
+"""
+Show information to the user as to what can be dispensed.
+"""
def scroll_options(username, mk, welcome = False):
+ # If the user has just logged in, show them their balance
if welcome:
# Balance checking
acct, unused = Popen(['dispense', 'acct', username], close_fds=True, stdout=PIPE).communicate()
msg = []
choices = ' '*10+'CHOICES: '
- # Get coke contents
+ # Show what is in the coke machine
cokes = []
for i in range(0, 7):
args = ('dispense', 'iteminfo', 'coke:%i' % i)
if slot_name == 'dead': continue
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 )
-
+ # Show the final few options
choices += '55-DOOR '
choices += 'OR ANOTHER SNACK. '
choices += '99 TO READ AGAIN. '
choices += 'CHOICE? '
msg.append((choices, False, None))
+ # Send it to the display
mk.set_messages(msg)
+
+"""
+Verify the users pin
+"""
def _check_pin(uid, pin):
global _pin_uid
global _pin_uname
logging.info("Pin incorrect for %d",uid)
return pin == int(pinstr)
+"""
+Check if the users account has been disabled
+"""
def acct_is_disabled(name=None):
global _pin_uname
if name == None:
return True
return False
+"""
+Check that the user has a valid pin set
+"""
def has_good_pin(uid):
return _check_pin(uid, None) != None
+"""
+Verify the users pin.
+"""
def verify_user_pin(uid, pin, skip_pin_check=False):
if skip_pin_check or _check_pin(uid, pin) == True:
info = pwd.getpwuid(uid)
logging.info('refused pin for uid %d'%(uid))
return None
-
+"""
+In here just for fun.
+"""
def cookie(v):
seed(time())
messages = [' WASSUP! ', 'PINK FISH ', ' SECRETS ', ' ESKIMO ', ' FORTUNES ', 'MORE MONEY']
s += msg[i]
v.display(s)
+"""
+Format text so it will appear centered on the screen.
+"""
def center(str):
LEN = 10
return ' '*((LEN-len(str))/2)+str
+"""
+Configure the things that will appear on screen whil the machine is idling.
+"""
def setup_idlers(v):
global idlers, idler
idlers = [
disabled = [
]
+"""
+Go back to the default idler.
+"""
def reset_idler(v, vstatus, t = None):
global idlers, idler
idler = GreetingIdler(v, t)
vstatus.time_to_autologout = None
vstatus.change_state(STATE_IDLE, 1)
+"""
+Change to a random idler.
+"""
def choose_idler():
global idlers, idler
if idler:
idler.reset()
-
+"""
+Run every step while the machine is idling.
+"""
def idle_step(vstatus):
global idler
if idler.finished():
nextidle = IDLE_SPEED
vstatus.time_of_next_idlestep = time()+nextidle
-
-
+"""
+These next two events trigger no response in the code.
+"""
def handle_tick_event(event, params, v, vstatus):
# don't care right now.
pass
# don't care right now.
pass
-
+"""
+Don't do anything for this event.
+"""
def do_nothing(state, event, params, v, vstatus):
print "doing nothing (s,e,p)", state, " ", event, " ", params
pass
+"""
+These next few entrie tell us to do nothing while we are idling
+"""
def handle_getting_uid_idle(state, event, params, v, vstatus):
# don't care right now.
pass
# don't care right now.
pass
+"""
+While logged in and waiting for user input, slowly get closer to logging out.
+"""
def handle_get_selection_idle(state, event, params, v, vstatus):
global _last_card_id
# don't care right now.
# need to check
vstatus.mk.update_display()
-
-
+"""
+Triggered on user input while logged in.
+"""
def handle_get_selection_key(state, event, params, v, vstatus):
global _last_card_id
key = params
vstatus.time_to_autologout = None
vstatus.last_timeout_refresh = None
+"""
+Triggered when the user has entered the id of something they would like to purchase.
+"""
def make_selection(v, vstatus):
# should use sudo here
if vstatus.cur_selection == '55':
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('dispense -u "%s" door'%vstatus.username)
else:
ret = os.system('dispense door')
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
v.display('UNK ERROR')
sleep(1)
-
+"""
+Find the price of an item.
+"""
def price_check(v, vstatus):
if vstatus.cur_selection[1] == '8':
args = ('dispense', 'iteminfo', 'coke:' + vstatus.cur_selection[0])
dollarprice = "$%.2f" % ( price / 100.0 )
v.display(vstatus.cur_selection+' - %s'%dollarprice)
-
+"""
+Triggered when the user presses a button while entering their pin.
+"""
def handle_getting_pin_key(state, event, params, v, vstatus):
#print "handle_getting_pin_key (s,e,p)", state, " ", event, " ", params
key = params
return
-
+"""
+Triggered when the user presses a button while entering their user id.
+"""
def handle_getting_uid_key(state, event, params, v, vstatus):
#print "handle_getting_uid_key (s,e,p)", state, " ", event, " ", params
key = params
vstatus.change_state(STATE_GETTING_PIN)
return
-
+"""
+Triggered when a key is pressed and the machine is idling.
+"""
def handle_idle_key(state, event, params, v, vstatus):
#print "handle_idle_key (s,e,p)", state, " ", event, " ", params
vstatus.change_state(STATE_GETTING_UID)
run_handler(event, key, v, vstatus)
-
+"""
+What to do when there is nothing to do.
+"""
def handle_idle_tick(state, event, params, v, vstatus):
### State idling
if vstatus.mk.done():
run_handler(event, params, v, vstatus)
sleep(0.05)
+"""
+Manages the beeps for the grandfather clock
+"""
def beep_on(when, before=0):
start = int(when - before)
end = int(when)
if go_idle and vstatus.mk.done():
vstatus.change_state(STATE_IDLE,1)
+"""
+What to do when the door is open.
+"""
def handle_door_idle(state, event, params, v, vstatus):
def twiddle(clock,v,wise = 2):
if (clock % 4 == 0):
else:
twiddle(now, v, wise=0)
-
+"""
+What to do when the door is opened or closed.
+"""
def handle_door_event(state, event, params, v, vstatus):
if params == 0: #door open
vstatus.change_state(STATE_DOOR_OPENING)
logging.warning('Leaving open door mode')
v.display("-YUM YUM!-")
-
+"""
+Triggered when a user swipes their caed, and the machine is logged out.
+"""
def handle_mifare_event(state, event, params, v, vstatus):
global _last_card_id
card_id = params
reset_idler(v, vstatus, 2)
return
+"""
+Triggered when a user swipes their card and the machine is logged in.
+"""
def handle_mifare_add_user_event(state, event, params, v, vstatus):
global _last_card_id
card_id = params
def return_to_idle(state,event,params,v,vstatus):
reset_idler(v, vstatus)
+"""
+Maps what to do when the state changes.
+"""
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_GRANDFATHER_CLOCK,KEY,2)] = do_nothing
vstatus.state_table[(STATE_GRANDFATHER_CLOCK,MIFARE,1)] = handle_mifare_event
+"""
+Get what to do on a state change.
+"""
def get_state_table_handler(vstatus, state, event, counter):
return vstatus.state_table[(state,event,counter)]
setup_idlers(v)
reset_idler(v, vstatus)
- # This main loop was hideous and the work of the devil.
- # This has now been fixed (mostly) - mtearle
- #
- #
- # notes for later surgery
- # (event, counter, ' ')
- # V
- # d[ ] = (method)
- #
- # ( return state - not currently implemented )
-
while True:
if USE_DB:
try:
run_handler(event, params, v, vstatus)
-# logging.debug('Got event: ' + repr(e))
-
-
def run_handler(event, params, v, vstatus):
handler = get_state_table_handler(vstatus,vstatus.state,event,vstatus.counter)
if handler:
handler(vstatus.state, event, params, v, vstatus)
+"""
+Connect to the machine.
+"""
def connect_to_vend(options, cf):
if options.use_lat:
return rfh, wfh
+"""
+Parse arguments from the command line
+"""
def parse_args():
from optparse import OptionParser
return options
-config_options = {
- 'DBServer': ('Database', 'Server'),
- 'DBName': ('Database', 'Name'),
- 'DBUser': ('VendingMachine', 'DBUser'),
- 'DBPassword': ('VendingMachine', 'DBPassword'),
-
- 'ServiceName': ('VendingMachine', 'ServiceName'),
- 'ServicePassword': ('VendingMachine', 'Password'),
-
- 'ServerName': ('DecServer', 'Name'),
- 'ConnectPassword': ('DecServer', 'ConnectPassword'),
- 'PrivPassword': ('DecServer', 'PrivPassword'),
- }
-
-class VendConfigFile:
- def __init__(self, config_file, options):
- try:
- cp = ConfigParser.ConfigParser()
- cp.read(config_file)
-
- for option in options:
- section, name = options[option]
- value = cp.get(section, name)
- self.__dict__[option] = value
-
- except ConfigParser.Error, e:
- raise SystemExit("Error reading config file "+config_file+": " + str(e))
-
def create_pid_file(name):
try:
pid_file = file(name, 'w')