class Matemat: log = getLogger('MatematSim') def __init__(self): pass @flogger(log) def writeLCD(self, msg): self.log.info('writeLCD(): msg=%s' % msg) @flogger(log) def getPriceline(self): while True: try: print 'Priceline?' p = int(sys.stdin.readline().strip()) self.log.debug('priceline=%s' % p) return p except ValueError: pass @flogger(log) def serve(self, priceline): self.log.info('priceline=%s' % priceline) # always serve return True @flogger(log) def completeserve(self): return True
class SerialInterface: log = getLogger('SerialInterface') @flogger(log) def __init__ ( self, path2device, baudrate, timeout=0): self.ser = serial.Serial(path2device, baudrate) self.ser.flushInput() self.ser.flushOutput() if timeout: self.ser.setTimeout(timeout) self.seriallog = open("/tmp/seriallog","w"); def writeMessage(self,message): enc = "\\0" + message.replace('\\','\\\\') + "\\1"; self.log.debug('writing %s' % enc) self.ser.write(enc) def readMessage(self): data = "" escaped = False stop = False start = False while True: c = self.ser.read(1) if len(c) == 0: #A timout occured self.log.warning('TIMEOUT') return False # print "c=", c # continue if escaped: if c == '0': start = True elif c == '1': stop = True elif c == '\\': d = '\\' escaped = False elif c == '\\': escaped = 1 else: d = c if start: start = False elif stop: if data[0] == 'D': message = '%f %s'%(time.time(), data[2:]) self.log.info('serial debug message: %d %s'%(len(data), data)) self.seriallog.write(message+"\n") self.seriallog.flush() #print message data = "" stop = False else: self.log.debug('received message: len=%d data=%s'%(len(data),data)) return data elif escaped == False: data += str(d)
class Checkout(threading.Thread): log = getLogger('Checkout') @flogger(log) def __init__(self): threading.Thread.__init__(self) self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #self.sock.setblocking(0) self.sock.bind((config.get('checkout', 'listen_ip'), config.getint('checkout', 'listen_port'))) self.matemat = matemat.Matemat() @flogger(log) def go(self): self.matemat.writeLCD('OBEY AND CONSUME') while not self.gotPurse: self.waitForSocket() if not self.processCommand(): return credit = self.token.eot() self.log.debug('credit=%s' % credit) self.report('Credit: %s' % credit) priceline = None while 1: if self.checkAbort(): return priceline = self.matemat.getPriceline() if priceline == -1: self.report('TIMEOUT', 3) return elif priceline != 0: self.log.info('priceline=%s' % priceline) break time.sleep(0.01) assets = self.token.assets(priceline) if assets < 0: self.report('Not enough credits!', 3) return self.token.finish(priceline) if self.matemat.serve(priceline): self.log.info('Serving %s' % priceline) self.report('%i left! kthxbye' % assets, 3) else: self.log.info('Failed to serve %s' % priceline) self.report('Failed to serve!', 3) self.token.rollback(priceline) return if False: #not self.matemat.completeserve(): self.log.info('Failed to complete serve %s' % priceline) self.report('Failed to cserve!', 3) self.token.rollback(priceline) @flogger(log) def report(self, msg, wait=0): self.matemat.writeLCD(msg) if wait != 0: time.sleep(wait) @flogger(log) def waitForSocket(self, timeout=None): r = select([self.sock], [], [], timeout) return len(r[0]) == 1 @flogger(log) def checkAbort(self): if self.waitForSocket(timeout=0): return self.processCommand(checkAbort=True) return False @flogger(log) def processCommand(self, checkAbort=False): data, self.raddr = self.sock.recvfrom(128) data.strip() if len(data) == 0: return cmd = data[:2] self.log.info('cmd=%s' % cmd) data = data[2:].strip() self.log.info('data=%s' % data) if checkAbort: return cmd == 'Ab' ret = False if cmd == 'Rd': if self.idle: self.send('READY') ret = True elif cmd == 'Ab': pass elif cmd == 'Bp': if len(data) == 0: self.report('ERR: Bad Purse!', 3) else: self.report('ERR: %s' % data[:15], 3) elif cmd == 'Td': self.gotPurse = True ret = True elif cmd == 'Tc': #self.report('Reading tokens...') self.token.check(data) self.report('Credit: %s' % self.token.tokencount) self.send('OK') ret = True elif cmd == 'Dm': self.report(data[:20], 3) return ret @flogger(log) def send(self, msg): self.log.info('msg=%s' % msg) return self.sock.sendto(msg, self.raddr) == 0 @flogger(log) def run(self): self.token = tokens.Token() while 1: self.idle = True self.gotPurse = False self.go() self.token.clear()
class CheckoutOld(threading.Thread): IDLE, COUNTING, CHECKING, WAITING, SERVING, CHECKINGSERVE, ABORTING,\ WAITSTATE, REPORTING = range(9) log = getLogger('Checkout') @flogger(log) def __init__(self, test=False): threading.Thread.__init__(self) self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setblocking(0) self.socket.bind((config.get('checkout', 'listen_ip'), config.getint('checkout', 'listen_port'))) self.matemat = matemat.Matemat() self.state = self.IDLE self.newstate = True self.served = False self.waiting = 0 @flogger(log) def send(self, msg): self.log.info('msg=%s' % msg) # print "sending",msg sent = self.socket.sendto(msg, self.raddr) if sent == 0: return False else: return True @flogger(log) def checkState(self): if self.waiting: if time.time() >= self.waiting: self.log.debug('setting state ' + str(self.nextstate)) self.state = self.nextstate self.newstate = True self.waiting = False @flogger(log) def setState(self, nextstate, wait=0): self.log.debug('nextstate=%d wait%d' % (nextstate, wait)) self.waiting = time.time() + wait self.nextstate = nextstate self.state = self.WAITSTATE @flogger(log) def fetchCommand(self): try: data, self.raddr = self.socket.recvfrom(64) data.strip() if len(data) > 0: self.cmd = "%s%s" % (data[0], data[1]) self.log.info('cmd=%s' % self.cmd) self.data = data[2:].strip() self.log.info('data=%s' % self.data) return True except: pass return False @flogger(log) def reset(self): if self.served: self.token.finish(0) self.token.tokenreset = True self.matemat.writeLCD("OBEY AND CONSUME") self.served = False @flogger(log) def pay(self): self.token.pay() @flogger(log) def run(self): self.token = tokens.Token() #has to be in this thread while 1: self.checkState() if (self.state == self.IDLE or self.state == self.COUNTING) and \ select([self.socket],[],[]) and self.fetchCommand(): if not self.command(): self.log.info('command failed') self.send("FAIL") self.process() def process(self): self.log.debug('processing state %d' % self.state) if self.state == self.IDLE: self.idle() elif self.state == self.COUNTING: if self.newstate: self.newstate = False self.socket.setblocking(1) self.matemat.writeLCD("Reading tokens") if self.tokendata: self.token.check(self.tokendata) self.send("OK") #print time.time() self.tokendata = "" elif self.state == self.ABORTING: self.abort() elif self.state == self.WAITING: self.wait() elif self.state == self.CHECKING: self.check() elif self.state == self.SERVING: self.serve() elif self.state == self.CHECKINGSERVE: self.checkserve() elif self.state == self.REPORTING: if self.newstate: self.newstate = False self.matemat.writeLCD(self.report) self.setState(self.IDLE, 3) def idle(self): if self.newstate: self.newstate = False self.reset() #time.sleep(0.1) def abort(self): if self.newstate: self.newstate = False self.matemat.writeLCD("aborting") self.setState(self.IDLE, 3) def wait(self): #sys.exit(0) if self.newstate: self.newstate = False self.credit = self.token.eot() self.log.debug('credit=%s' % self.credit) self.matemat.writeLCD("Credit: %s" % self.credit) self.priceline = self.matemat.getPriceline() if self.priceline == -1: self.matemat.writeLCD("TIMEOUT") self.setState(self.ABORTING, 3) elif self.priceline != 0: self.log.info('priceline=%s' % self.priceline) self.setState(self.CHECKING) time.sleep(0.01) def check(self): liquidity = self.token.assets(self.priceline) if liquidity == False: self.matemat.writeLCD("Not enough credits") self.setState(self.IDLE, 3) else: self.setState(self.SERVING) def serve(self): if self.matemat.serve(self.priceline): self.log.info('Serving %s' % self.priceline) self.matemat.writeLCD("Enjoy it") self.served = True self.setState(self.CHECKINGSERVE) else: self.log.info('Failed to serve %s' % self.priceline) self.matemat.writeLCD("Failed to serve") served = False self.setState(self.ABORTING, 3) def checkserve(self): if not self.matemat.completeserve(): self.log.info('Failed to serve %s' % self.priceline) self.matemat.writeLCD("Failed to serve") served = False self.setState(self.ABORTING, 3) else: self.setState(self.IDLE, 3) @flogger(log) def command(self): if self.cmd == "Ta": if self.token.add(tokendata): self.send("OK") return True return False elif self.cmd == "Rd": if self.state == self.IDLE: self.send("READY") return True return False elif self.cmd == "Ab": if self.state != self.IDLE and self.nextstate != self.IDLE: self.setState(self.ABORTING) return False elif self.cmd == "Tc": if self.state == self.IDLE or self.state == self.COUNTING: self.tokendata = self.data if self.state == self.IDLE: self.setState(self.COUNTING) return True else: return False return True elif self.cmd == "Td": if self.state == self.COUNTING: self.setState(self.WAITING) self.socket.setblocking(0) return True return False elif self.cmd == "Bp": self.setState(self.REPORTING) self.report = "Bad Purse!" self.socket.setblocking(0)
class Cashier: log = getLogger('Cashier') @flogger(log) def __init__(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.connect((config.get('cashier', 'checkout_ip'), config.getint('cashier', 'checkout_port'))) self.socket.settimeout(1) @flogger(log) def send(self, msg): sent = self.socket.send(msg) if sent != 0: self.log.debug('"%s": Send OK' % msg) return True else: self.log.debug('"%s": Send failed' % msg) return False @flogger(log) def recv(self, expect): try: data = self.socket.recv(64) except: return False data = data.strip() if data == expect: self.log.debug('"%s": Receive OK' % expect) return True else: self.log.debug('"%s": Receive failed' % expect) return False @flogger(log) def isReady(self): sent = self.send("Rd") if sent: rcvd = self.recv("READY") else: return False if rcvd: return True else: return False @flogger(log) def reportBadPurse(self, message=None): if message: sent = self.send("Bp%s" % message) else: sent = self.send("Bp") @flogger(log) def abort(self): sent = self.send("Ab") if sent: rcvd = self.recv("OK") else: return False if rcvd: return True else: return False @flogger(log) def checkToken(self, token): sent = self.send("Tc%s" % token) if sent: rcvd = self.recv("OK") else: return False if rcvd: self.log.debug('"%s": True' % token) return True else: self.log.debug('"%s": False' % token) return False @flogger(log) def checkCredit(self): sent = self.send("Td") @flogger(log) def display(self, message): sent = self.send("Dm%s" % message)
class Matemat(threading.Thread): log = getLogger('Matemat') messages = Queue.Queue() def __init__(self): threading.Thread.__init__(self) self.interface = upay.serialinterface.SerialInterface( '/dev/ttyS0', 115200, 5) def run(self): while 1: message = self.interface.readMessage() self.messages.put(message) def getMessage(self): return self.messages.get(block=True) @flogger(log) def _waitForReply(self, reply): self.log.debug('reply=%s' % reply) while True: msg = self.getMessage() if msg == False: return False if msg in reply: self.log.debug('msg=%s' % msg) return msg @flogger(log) def writeLCD(self, msg): self.log.info('writeLCD(): msg=%s' % msg) msg = "d" + msg self.interface.writeMessage(msg) return self._waitForReply(["dD"]) @flogger(log) def getPriceline(self): self.interface.writeMessage("p") while True: msg = self.getMessage() if msg == False: return -1 if msg[0] == 'p': self.log.debug('priceline=%s' % msg[2]) return int(msg[2]) @flogger(log) def serve(self, priceline): self.log.info('priceline=%s' % priceline) self.interface.writeMessage("s" + str(priceline)) ret = self._waitForReply(["sO", "sN"]) if ret == False: return False if ret == "sN": return False return True @flogger(log) def completeserve(self): return self._waitForReply(["sD"])