@@ -91,6 +91,33 @@ def decorator(self, *args, **kwargs):
9191 return decorator
9292
9393
94+ def i2c_lock (fn ):
95+ """Attempt to get a lock on the I2C bus used for Notecard comms."""
96+
97+ def decorator (self , * args , ** kwargs ):
98+ retries = 5
99+ while use_i2c_lock and retries != 0 :
100+ if self .i2c .try_lock ():
101+ break
102+
103+ retries -= 1
104+ # Try again after 100 ms.
105+ time .sleep (.1 )
106+
107+ if retries == 0 :
108+ raise Exception ('Failed to acquire I2C lock.' )
109+
110+ try :
111+ ret = fn (self , * args , ** kwargs )
112+ finally :
113+ if use_i2c_lock :
114+ self .i2c .unlock ()
115+
116+ return ret
117+
118+ return decorator
119+
120+
94121class Notecard :
95122 """Base Notecard class.
96123
@@ -150,24 +177,25 @@ def _transmit(self, req):
150177 req = self ._preprocess_req (req )
151178 req_json = _prepare_request (req , self ._debug )
152179
153- transaction_timeout_secs = 30
154- if self ._transaction_manager :
155- self ._transaction_manager .start (transaction_timeout_secs )
156-
157- seg_off = 0
158- seg_left = len (req_json )
159- while seg_left > 0 :
160- seg_len = seg_left
161- if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN :
162- seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
180+ try :
181+ transaction_timeout_secs = 30
182+ if self ._transaction_manager :
183+ self ._transaction_manager .start (transaction_timeout_secs )
163184
164- self .uart .write (req_json [seg_off :seg_off + seg_len ].encode ('utf-8' ))
165- seg_off += seg_len
166- seg_left -= seg_len
167- time .sleep (CARD_REQUEST_SEGMENT_DELAY_MS / 1000 )
185+ seg_off = 0
186+ seg_left = len (req_json )
187+ while seg_left > 0 :
188+ seg_len = seg_left
189+ if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN :
190+ seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
168191
169- if self ._transaction_manager :
170- self ._transaction_manager .stop ()
192+ self .uart .write (req_json [seg_off :seg_off + seg_len ].encode ('utf-8' ))
193+ seg_off += seg_len
194+ seg_left -= seg_len
195+ time .sleep (CARD_REQUEST_SEGMENT_DELAY_MS / 1000 )
196+ finally :
197+ if self ._transaction_manager :
198+ self ._transaction_manager .stop ()
171199
172200 def _read_byte (self ):
173201 """Read a single byte from the Notecard."""
@@ -325,84 +353,51 @@ def _receive(self, timeout_secs, chunk_delay_secs, wait_for_newline):
325353 # behavior of other SDKs (e.g. note-c).
326354 time .sleep (chunk_delay_secs )
327355
328- if ( timeout_secs != 0 and has_timed_out (start , timeout_secs ) ):
356+ if timeout_secs != 0 and has_timed_out (start , timeout_secs ):
329357 raise Exception ("Timed out while reading data from the Notecard." )
330358
331359 return read_data
332360
333- def Command (self , req ):
334- """Perform a Notecard command and exit with no response."""
361+ def _transmit (self , req ):
335362 req = self ._preprocess_req (req )
336- if 'cmd' not in req :
337- raise Exception ("Please use 'cmd' instead of 'req'" )
338-
339363 req_json = _prepare_request (req , self ._debug )
340364
341- while not self .lock ():
342- pass
343-
344365 try :
345366 transaction_timeout_secs = 30
346367 if self ._transaction_manager :
347368 self ._transaction_manager .start (transaction_timeout_secs )
348369
349370 self ._send_payload (req_json )
350371 finally :
351- self .unlock ()
352372 if self ._transaction_manager :
353373 self ._transaction_manager .stop ()
354374
355- def Transaction (self , req ):
356- """Perform a Notecard transaction and return the result."""
357- req = self ._preprocess_req (req )
358-
359- req_json = _prepare_request (req , self ._debug )
360- rsp_json = ""
361-
362- while not self .lock ():
363- pass
375+ @i2c_lock
376+ def Command (self , req ):
377+ """Perform a Notecard command and exit with no response."""
378+ if 'cmd' not in req :
379+ raise Exception ("Please use 'cmd' instead of 'req'" )
364380
365- try :
366- transaction_timeout_secs = 30
367- if self ._transaction_manager :
368- self ._transaction_manager .start (transaction_timeout_secs )
381+ self ._transmit (req )
369382
370- self ._send_payload (req_json )
383+ @i2c_lock
384+ def Transaction (self , req ):
385+ """Perform a Notecard transaction and return the result."""
386+ self ._transmit (req )
371387
372- read_data = self ._receive (transaction_timeout_secs , 0.05 , True )
373- rsp_json = "" .join (map (chr , read_data ))
374- finally :
375- self .unlock ()
376- if self ._transaction_manager :
377- self ._transaction_manager .stop ()
388+ read_data = self ._receive (30 , 0.05 , True )
389+ rsp_json = "" .join (map (chr , read_data ))
378390
379391 if self ._debug :
380392 print (rsp_json .rstrip ())
381393
382394 return json .loads (rsp_json )
383395
396+ @i2c_lock
384397 def Reset (self ):
385398 """Reset the Notecard."""
386- while not self .lock ():
387- pass
388-
389- try :
390- # Read from the Notecard until there's nothing left to read.
391- self ._receive (0 , .001 , False )
392- finally :
393- self .unlock ()
394-
395- def lock (self ):
396- """Lock the I2C port so the host can interact with the Notecard."""
397- if use_i2c_lock :
398- return self .i2c .try_lock ()
399- return True
400-
401- def unlock (self ):
402- """Unlock the I2C port."""
403- if use_i2c_lock :
404- return self .i2c .unlock ()
405- return True
399+ # Read from the Notecard until there's nothing left to read.
400+ self ._receive (0 , .001 , False )
406401
407402 def __init__ (self , i2c , address , max_transfer , debug = False ):
408403 """Initialize the Notecard before a reset."""
0 commit comments