@@ -17,24 +17,37 @@ class Scratch:
1717 def __init__ (self , host = 'localhost' ):
1818 self .host = host
1919 self .port = 42001
20- self .connection = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
21- self .connect ()
20+ self .connect (poll = True )
2221 self .connected = 1
23- def connect (self ):
24- try :
25- self .connection .connect ((self .host , self .port ))
26- except socket .error as (err , message ):
27- if err == errno .ECONNREFUSED :
28- raise ScratchConnectionRefused ('Connection refused, try enabling remote sensor connections' )
29- elif err == errno .EISCONN :
22+
23+ def connect (self , poll = False ):
24+ """
25+ Creates a connection to the Scratch environment. If poll is True, blocks until
26+ Scratch is running, and listening for connections on port 42001, else connect()
27+ raises appropiate exceptions.
28+ """
29+ while True :
30+ try :
31+ # create the socket here not in __init__() to avoid errno 22 invalid argument
32+ self .connection = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
33+ self .connection .connect ((self .host , self .port ))
34+ except socket .error as (err , message ):
35+ if err == errno .EISCONN :
3036 raise ScratchConnectionEstablished ('Already connected to Scratch' )
37+ elif poll == True :
38+ continue
39+ elif err == errno .ECONNREFUSED :
40+ raise ScratchConnectionRefused ('Connection refused, try enabling remote sensor connections' )
3141 else :
3242 print (err , message )
3343 raise ScratchConnectionError (message )
44+ break
3445 self .connected = 1
46+
3547 def disconnect (self ):
3648 self .connection .close ()
3749 self .connected = 0
50+
3851 def send (self , message ):
3952 #credit to chalkmarrow from scratch.mit.edu
4053 n = len (message )
@@ -50,6 +63,7 @@ def send(self, message):
5063 raise ScratchConnectionError (message )
5164 else :
5265 raise ScratchConnectionError ('Not connected to Scratch' )
66+
5367 def sensorupdate (self , data ):
5468 """Takes a dictionary and writes a message using the keys as sensors, and the values as the update values"""
5569 if not isinstance (data , dict ):
@@ -58,6 +72,7 @@ def sensorupdate(self, data):
5872 for key in data .keys ():
5973 message = message + ' "' + key + '" ' + data [key ]
6074 self .send (message )
75+
6176 def broadcast (self , data ):
6277 """Takes a list of message strings and writes a broadcast message to scratch"""
6378 if not isinstance (data , list ):
@@ -66,8 +81,10 @@ def broadcast(self, data):
6681 for mess in data :
6782 message = message + ' "' + mess + '"'
6883 self .send (message )
84+
6985 def parse_message (self , message ):
7086 #TODO: parse sensorupdates with quotes in sensor names and values
87+ # make more readable
7188 if message :
7289 sensorupdate_re = 'sensor-update[ ](((?:\" ).[^\" ]*(?:\" ))[ ](?:\" |)(.[^\" ]*)(?:\" |)[ ])+'
7390 broadcast_re = 'broadcast[ ]\" .[^"]*\" '
@@ -87,7 +104,8 @@ def parse_message(self, message):
87104 if sensorupdates [i ][- 1 ] != '\" ' :
88105 j = i
89106 multisense = ''
90- #now loop through each word in list and find the word that ends with " which is the end of the variable name
107+ #now loop through each word in list and find the word
108+ #that ends with " which is the end of the variable name
91109 while j < len (sensorupdates ):
92110 multisense = multisense + ' ' + sensorupdates [j ]
93111 if sensorupdates [j ][- 1 ] == '\" ' :
@@ -114,32 +132,31 @@ def parse_message(self, message):
114132 return dict ([('sensor-update' , sensors ), ('broadcast' , broadcast )])
115133 else :
116134 return None
135+
117136 def receive (self , noparse = 0 ):
118137 """ Receives data from Scratch
119138 Arguments:
120- Optional:
121- noparse -- 0 to pass message through a parser and return the message as a data structure
122- 1 to not parse message, but format as a string
123- 2 to not parse message and not format as a string (returns raw message)
139+ noparse: 0 to pass message through a parser and return the message as a data structure
140+ 1 to not parse message, but format as a string
141+ 2 to not parse message and not format as a string (returns raw message)
124142 """
125-
126- try :
127- mess = self .connection .recv (1024 )
128- except socket .error as (errno , message ):
129- if errno == 107 or 9 :
130- raise ScratchConnectionError (errno , 'A connection must first be made to Scratch with Scratch.connect()' )
131- else :
132- raise ScratchConnectionError (errno , message )
143+ try :
144+ mess = self .connection .recv (1024 )
145+ except socket .error as (errno , message ):
146+ raise ScratchConnectionError (errno , message )
147+ if not mess :
148+ return None
133149 if noparse == 0 :
134150 return self .parse_message (repr (mess ))
135- if noparse == 1 :
151+ if noparse == 1 :
136152 return repr (mess )
137153 elif noparse == 2 :
138- return mess
154+ return mess
139155 else :
140156 return self .parse_message (repr (mess ))
141157
142158if __name__ == "__main__" :
159+ #runs and prints out raw messages received from Scratch
143160 try :
144161 s = Scratch ()
145162 except ScratchConnectionError , e :
0 commit comments