/[anoncvs]/projects/dispense2/sql-edition/servers/VendingMachine.py


UCC Code Repository

Diff of /projects/dispense2/sql-edition/servers/VendingMachine.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by dagobah, Fri Jun 25 15:33:12 2004 UTC revision 1.18 by dagobah, Fri Mar 2 12:33:13 2007 UTC
# Line 1  Line 1 
1    # vim:ts=4
2  import re  import re
3  from CRC import do_crc  from CRC import do_crc
4  from binascii import unhexlify  from select import select
5    import socket, logging
6    from time import time, sleep
7    
8  asynchronous_responses = [      '400', '401', # door open/closed  asynchronous_responses = [      '400', '401', # door open/closed
9                                  '610',        # switches changed                                  '610',        # switches changed
10                                    '200', '201', '202', '203', '204', '205', '206',
11                                    '207', '208', '209', '211', # key presses
12                           ]                           ]
13    DOOR = 1
14    SWITCH = 2
15    KEY = 3
16    TICK = 4
17    
18    class VendingException(Exception): pass
19    
20  class VendingMachine:  class VendingMachine:
21          def __init__(self, rfh, wfh):          def __init__(self, rfh, wfh):
22                    self.events = []
23                  self.secret = 'AAAAAAAAAAAAAAAA'                  self.secret = 'AAAAAAAAAAAAAAAA'
24                  self.rfh = rfh                  self.rfh = rfh
25                  self.wfh = wfh                  self.wfh = wfh
# Line 20  class VendingMachine: Line 32  class VendingMachine:
32                  self.wfh.write('PING\n')                  self.wfh.write('PING\n')
33                  code = ''                  code = ''
34                  while code != '000':                  while code != '000':
35                          (code, _) = self.get_response()                          code = self.get_response()[0]
36                    self.get_switches()
37    
38          def await_prompt(self):          def await_prompt(self):
39                  self.wfh.flush()                  self.wfh.flush()
# Line 28  class VendingMachine: Line 41  class VendingMachine:
41                  prefix = ''                  prefix = ''
42                  s = ''                  s = ''
43                  while True:                  while True:
44                          s = self.rfh.read(1)                          try:
45                          if s == '': raise Exception                                  s = self.rfh.read(1)
46                            except socket.error:
47                                    raise VendingException('failed to read input from vending machine')
48                            if s == '': raise VendingException('nothing read!')
49                            if (s != '#' and s != '%') and state == 1: prefix += s
50                          if s == '\n' or s == '\r':                          if s == '\n' or s == '\r':
51                                  state = 1                                  state = 1
52                                  prefix = ''                                  prefix = ''
# Line 39  class VendingMachine: Line 56  class VendingMachine:
56                                          self.challenge = None                                          self.challenge = None
57                                          return                                          return
58                                  if re.search('^[0-9a-fA-F]{4}$', prefix):                                  if re.search('^[0-9a-fA-F]{4}$', prefix):
59                                          self.challenge = unhexlify(prefix)                                          self.challenge = int(prefix, 16)
60                                          return                                          return
61    
62          def get_response(self):          def get_response(self, async = False):
63                  self.wfh.flush()                  self.wfh.flush()
64                  while True:                  while True:
65                          s = ''                          s = ''
66                          while s == '':                          while s == '':
67                                  s = self.rfh.readline()                                  s = self.rfh.readline()
68                                  if s == '': return None                                  if s == '':
69                                            raise VendingException('Input socket has closed!')
70                                  s = s.strip('\r\n')                                  s = s.strip('\r\n')
71                          code = s[0:3]                          code = s[0:3]
72                          text = s[4:]                          text = s[4:]
73                          if code in asynchronous_responses:                          if code in asynchronous_responses:
74                                  self.handle_event(code, text)                                  self.handle_event(code, text)
75                                    if async: return None
76                          else:                          else:
77                                  self.await_prompt()                                  self.await_prompt()
78                                  return (code, text)                                  return (code, text)
79    
80            def get_switches(self):
81                    self.wfh.write('S\n')
82                    (code, text) = self.get_response()
83                    if code != '600':
84                            return (False, code, text)
85                    self.interpret_switches(text)
86                    return (True, code, text)
87    
88            def interpret_switches(self, text):
89                    self.switches = (int(text[0:2], 16) << 8) | int(text[3:5], 16)
90    
91          def handle_event(self, code, text):          def handle_event(self, code, text):
92                  pass                  if code == '400':
93                            self.events.append((DOOR, 1))
94                    elif code == '401':
95                            self.events.append((DOOR, 0))
96                    elif code == '610':
97                            # NOP this. Nothing handles this yet.
98                            #self.events.append((SWITCH, None))
99                            self.interpret_switches(text)
100                    elif code[0] == '2':
101                            self.events.append((KEY, int(code[1:3])))
102                    else:
103                            logging.warning('Unhandled event! (%s %s)\n'%(code,text))
104    
105          def authed_message(self, message):          def authed_message(self, message):
106                  if self.challenge == None:                  if self.challenge == None:
# Line 77  class VendingMachine: Line 118  class VendingMachine:
118          def vend(self, item):          def vend(self, item):
119                  if not re.search('^[0-9][0-9]$', item):                  if not re.search('^[0-9][0-9]$', item):
120                          return (False, 'Invalid item requested (%s)'%item)                          return (False, 'Invalid item requested (%s)'%item)
121                  self.wfh.write(self.authed_message(('V%s\n'%item)+'\n'))                  self.wfh.write(self.authed_message(('V%s'%item))+'\n')
122                  (code, string) = self.get_response()                  (code, string) = self.get_response()
123                  return (code, string)                  return (code == '100', code, string)
124    
125          def beep(self, duration = None, synchronous = True):          def beep(self, duration = None, synchronous = True):
126                  msg = 'B'                  msg = 'B'
# Line 101  class VendingMachine: Line 142  class VendingMachine:
142                          msg += '%02x'%duration                          msg += '%02x'%duration
143                  self.wfh.write(msg+'\n')                  self.wfh.write(msg+'\n')
144                  (code, string) = self.get_response()                  (code, string) = self.get_response()
145                  # FIXME: workaround a bug in rom W. should be just: return (code == '500', code, string)                  return (code == '501', code, string)
                 return (code == '500' or code == '501', code, string)  
146    
147          def display(self, string):          def display(self, string):
148                  if len(string) > 10:                  if len(string) > 10:
149                          string = string[0:10]                          string = string[0:10]
150                    string = re.sub('(.)\.', lambda match: '.'+match.group(1), string)
151                  self.wfh.write('D'+string+'\n')                  self.wfh.write('D'+string+'\n')
152                  (code, string) = self.get_response()                  (code, string) = self.get_response()
153                  return (code == '300', code, string)                  return (code == '300', code, string)
154    
155            def next_event(self, timeout = None):
156                    # we don't want to buffer in the serial port, so we get all the events
157                    # we can ASAP.
158                    if timeout < 0: timeout = 0
159                    if len(self.events) > 0: timeout = 0
160                    while True:
161                            (r, _, _) = select([self.rfh], [], [], timeout)
162                            if r:
163                                    self.get_response(async = True)
164                                    timeout = 0
165                            else:
166                                    break
167                    if len(self.events) == 0: return (TICK, time())
168                    ret = self.events[0]
169                    del self.events[0]
170                    return ret

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.18

Managed by UCC Webmasters ViewVC Help
Powered by ViewVC 1.1.26