Package joy :: Module scratch
[hide private]
[frames] | no frames]

Source Code for Module joy.scratch

  1  import struct 
  2  import socket 
  3  import time 
  4  import sys 
  5  import select 
  6  import re 
  7  from warnings import warn 
8 9 -class FramedSock( object ):
10 - def __init__(self, host="127.0.0.1", port=42001):
11 self.addr = (host,port) 12 self.iterLimit = 32 13 self.sock = None
14
15 - def isConnected( self ):
16 return self.sock is not None
17
18 - def connect( self ):
19 if self.sock != None: 20 raise ValueError("Socket is already open") 21 self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 22 self.sock.connect(self.addr)
23
24 - def close( self ):
25 if self.sock is not None: 26 self.sock.close() 27 self.sock = None
28
29 - def recv( self ):
30 hdr = self.sock.recv(4) 31 if len(hdr) != 4: 32 raise IOError("Failed to read header from socket") 33 H = struct.unpack(">L",hdr)[0] 34 N = 0 35 msg = [] 36 while N<H: 37 msg.append( self.sock.recv(H-N) ) 38 N += len(msg[-1]) 39 return "".join(msg)
40
41 - def send( self, msg ):
42 hdr = struct.pack(">L",len(msg)) 43 self.sock.send( hdr+msg )
44
45 - def recv_async( self, timeout=0.01 ):
46 if self.sock: 47 r,_,_ = select.select( [self.sock],[],[],timeout ) 48 if r: 49 return self.recv() 50 return None
51
52 - def __iter__(self):
53 for k in xrange(self.iterLimit): 54 msg = self.recv_async() 55 if msg is None: 56 break 57 yield msg
58
59 -class Board( object ):
60 - def __init__(self, host="127.0.0.1", port=42001 ):
61 self._fsk = FramedSock( host, port )
62 63 REX_STR = re.compile('\s*(?:"(([^"]|"")*)")\s*') 64 REX_VAL = re.compile('\s*((?:-?\d*(.\d+)?)|(?:\w[-A-Za-z0-9_]*))\s*') 65 REX_CMD = re.compile('\s*((?:sensor-update)|(?:broadcast))\s*') 66 @classmethod
67 - def _tokenize( cls, msg ):
68 tok = [] 69 # Tokenize the command portion 70 m = cls.REX_CMD.match(msg) 71 if not m: return tok 72 tok.append( m.group(1) ) 73 msg = msg[len(m.group(0)):] 74 # Tokenize the remainder 75 while msg: 76 m = cls.REX_STR.match(msg) 77 if m: 78 tok.append( m.group(1).replace('""','"') ) 79 msg = msg[len(m.group(0)):] 80 continue 81 m = cls.REX_VAL.match(msg) 82 if m: 83 tok.append( m.group(1) ) 84 msg = msg[len(m.group(0)):] 85 continue 86 raise SyntaxError("Cannot parse '%s'" % msg) 87 return tok
88
89 - def _doSensorUpdate( self, tok, upd ):
90 if len(tok) & 1: 91 warn('Sensor-update with odd number of tokens; skipping last') 92 tok.pop() 93 while tok: 94 nm = tok.pop(0) 95 val = tok.pop(0) 96 if val=="true": val = True 97 elif val=="false": val = False 98 elif val[0] in "-0123456789": val = float(val) 99 upd[nm] = val
100
101 - def close( self ):
102 self._fsk.close()
103
104 - def _autoConnect( self ):
105 if self._fsk.isConnected(): return True 106 try: 107 self._fsk.connect() 108 return True 109 except IOError, ioe: 110 sys.stderr.write( "Failed to connect: %s\n" % ioe ) 111 self._fsk.close() 112 return False
113
114 - def poll( self ):
115 if not self._autoConnect(): return None,None 116 # Poll for messages on socket 117 upds = {} 118 evts = set() 119 for msg in self._fsk: 120 tok = self._tokenize(msg) 121 if tok is None: 122 warn("Failed to parse Scratch message '%s'" % msg) 123 continue 124 # If 'sensor-update' message 125 if tok[0][0]=='s': 126 self._doSensorUpdate(tok[1:],upds) 127 elif tok[0][0]=='b': 128 for nm in tok[1:]: 129 evts.add(nm) 130 return upds, evts
131
132 - def sensorUpdate(self, **kw):
133 if not self._autoConnect(): return 134 msg = ['sensor-update'] 135 for k,v in kw.iteritems(): 136 msg.append('"%s"' % k) 137 msg.append(str(v)) 138 self._fsk.send( " ".join(msg) )
139
140 - def broadcast(self,*arg):
141 if not self._autoConnect(): return 142 for txt in arg: 143 txt = txt.replace('"','""') 144 self._fsk.send( 'broadcast "%s"' % txt )
145 146 147 if __name__=="__main__": 148 print "Connecting to Scratch at default host:port" 149 try: 150 sk = FramedSock() 151 sk.connect() 152 t0 = time.time() 153 while True: 154 msg = sk.recv() 155 sys.stdout.write("%6.2f %s\n" % (time.time()-t0,msg)) 156 sys.stdout.flush() 157 finally: 158 sk.close() 159