Skip to content

Commit 9d752a3

Browse files
committed
Make I2C improvements.
- For functions that need to acquire the I2C lock, use a new decorator, i2c_lock. This decorator also adds new functionality. Specifically, it has a timeout if it fails to get the lock. - Consolidate common code between I2C Transaction and Command into a new internal function, _transmit. This is the same pattern used for serial.
1 parent 6ba782d commit 9d752a3

File tree

1 file changed

+45
-48
lines changed

1 file changed

+45
-48
lines changed

notecard/notecard.py

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
94121
class Notecard:
95122
"""Base Notecard class.
96123
@@ -330,79 +357,49 @@ def _receive(self, timeout_secs, chunk_delay_secs, wait_for_newline):
330357

331358
return read_data
332359

333-
def Command(self, req):
334-
"""Perform a Notecard command and exit with no response."""
360+
def _transmit(self, req):
335361
req = self._preprocess_req(req)
336-
if 'cmd' not in req:
337-
raise Exception("Please use 'cmd' instead of 'req'")
338-
339362
req_json = _prepare_request(req, self._debug)
340363

341-
while not self.lock():
342-
pass
343-
344364
try:
345365
transaction_timeout_secs = 30
346366
if self._transaction_manager:
347367
self._transaction_manager.start(transaction_timeout_secs)
348368

349369
self._send_payload(req_json)
350370
finally:
351-
self.unlock()
352371
if self._transaction_manager:
353372
self._transaction_manager.stop()
354373

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
374+
@i2c_lock
375+
def Command(self, req):
376+
"""Perform a Notecard command and exit with no response."""
377+
if 'cmd' not in req:
378+
raise Exception("Please use 'cmd' instead of 'req'")
364379

365-
try:
366-
transaction_timeout_secs = 30
367-
if self._transaction_manager:
368-
self._transaction_manager.start(transaction_timeout_secs)
380+
self._transmit(req)
369381

370-
self._send_payload(req_json)
382+
@i2c_lock
383+
def Transaction(self, req):
384+
"""Perform a Notecard transaction and return the result."""
385+
self._transmit(req)
371386

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()
387+
read_data = self._receive(transaction_timeout_secs, 0.05, True)
388+
rsp_json = "".join(map(chr, read_data))
378389

379390
if self._debug:
380391
print(rsp_json.rstrip())
381392

382393
return json.loads(rsp_json)
383394

395+
396+
@i2c_lock
384397
def Reset(self):
385398
"""Reset the Notecard."""
386-
while not self.lock():
387-
pass
388399

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
400+
# Read from the Notecard until there's nothing left to read.
401+
self._receive(0, .001, False)
402+
406403

407404
def __init__(self, i2c, address, max_transfer, debug=False):
408405
"""Initialize the Notecard before a reset."""

0 commit comments

Comments
 (0)