Skip to content

Commit 47f250a

Browse files
committed
Address review feedback.
1 parent 585ce82 commit 47f250a

File tree

1 file changed

+83
-48
lines changed

1 file changed

+83
-48
lines changed

notecard/notecard.py

Lines changed: 83 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,18 @@
4040
use_periphery = False
4141
use_serial_lock = False
4242

43-
if sys.implementation.name == 'cpython':
44-
if sys.platform == 'linux' or sys.platform == 'linux2':
45-
use_periphery = True
46-
from periphery import I2C
43+
if sys.implementation.name == 'cpython' and (sys.platform == 'linux' or
44+
sys.platform == 'linux2'):
4745

48-
use_serial_lock = True
49-
from filelock import Timeout, FileLock
46+
use_periphery = True
47+
from periphery import I2C
48+
49+
use_serial_lock = True
50+
from filelock import FileLock
51+
from filelock import Timeout as SerialLockTimeout
52+
else:
53+
class SerialLockTimeout(Exception):
54+
pass
5055

5156
use_i2c_lock = not use_periphery and sys.implementation.name != 'micropython'
5257

@@ -75,18 +80,28 @@ def _prepare_request(req, debug=False):
7580
return req_json
7681

7782

83+
class NullContextManager:
84+
def __enter__(self):
85+
pass
86+
87+
def __exit__(self, exc_type, exc_value, traceback):
88+
pass
89+
90+
91+
class NoOpSerialLock():
92+
def acquire(*args, **kwargs):
93+
return NullContextManager()
94+
95+
7896
def serial_lock(fn):
7997
"""Attempt to get a lock on the serial channel used for Notecard comms."""
8098

8199
def decorator(self, *args, **kwargs):
82-
if use_serial_lock:
83-
try:
84-
with self.lock.acquire(timeout=5):
85-
return fn(self, *args, **kwargs)
86-
except Timeout:
87-
raise Exception('Notecard in use')
88-
else:
89-
return fn(self, *args, **kwargs)
100+
try:
101+
with self.lock.acquire(timeout=5):
102+
return fn(self, *args, **kwargs)
103+
except SerialLockTimeout:
104+
raise Exception('Notecard in use')
90105

91106
return decorator
92107

@@ -146,58 +161,67 @@ def SetTransactionPins(self, rtx_pin, ctx_pin):
146161
class OpenSerial(Notecard):
147162
"""Notecard class for Serial communication."""
148163

164+
@serial_lock
149165
def _transmit(self, req):
150166
req = self._preprocess_req(req)
151167
req_json = _prepare_request(req, self._debug)
152168

153-
transaction_timeout_secs = 30
154-
if self._transaction_manager:
155-
self._transaction_manager.start(transaction_timeout_secs)
169+
try:
170+
transaction_timeout_secs = 30
171+
if self._transaction_manager:
172+
self._transaction_manager.start(transaction_timeout_secs)
156173

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
174+
seg_off = 0
175+
seg_left = len(req_json)
176+
while seg_left > 0:
177+
seg_len = seg_left
178+
if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN:
179+
seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
163180

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)
181+
self.uart.write(req_json[seg_off:seg_off + seg_len].encode('utf-8'))
182+
seg_off += seg_len
183+
seg_left -= seg_len
184+
time.sleep(CARD_REQUEST_SEGMENT_DELAY_MS / 1000)
185+
finally:
186+
if self._transaction_manager:
187+
self._transaction_manager.stop()
168188

169-
if self._transaction_manager:
170-
self._transaction_manager.stop()
189+
@serial_lock
190+
def _transmit_and_receive(self, req):
191+
self._transmit(req)
171192

172-
def _read_byte(self):
173-
"""Read a single byte from the Notecard."""
174-
if sys.implementation.name == 'micropython':
175-
if not self.uart.any():
176-
return None
177-
elif sys.implementation.name == 'cpython':
178-
if self.uart.in_waiting == 0:
179-
return None
193+
rsp_json = self.uart.readline()
194+
if self._debug:
195+
print(rsp_json.rstrip())
196+
197+
return json.loads(rsp_json)
198+
199+
def _read_byte_micropython(self):
200+
"""Read a single byte from the Notecard (MicroPython)."""
201+
if not self.uart.any():
202+
return None
203+
return self.uart.read(1)
204+
205+
def _read_byte_cpython(self):
206+
"""Read a single byte from the Notecard (CPython)."""
207+
if self.uart.in_waiting == 0:
208+
return None
209+
return self.uart.read(1)
210+
211+
def _read_byte_circuitpython(self):
212+
"""Read a single byte from the Notecard (CircuitPython)."""
180213
return self.uart.read(1)
181214

182-
@serial_lock
183215
def Command(self, req):
184216
"""Send a command to the Notecard. The Notecard response is ignored."""
185217
if 'cmd' not in req:
186218
raise Exception("Please use 'cmd' instead of 'req'")
187219

188220
self._transmit(req)
189221

190-
@serial_lock
191222
def Transaction(self, req):
192223
"""Perform a Notecard transaction and return the result."""
193-
self._transmit(req)
194-
195-
rsp_json = self.uart.readline()
196-
if self._debug:
197-
print(rsp_json.rstrip())
198-
199-
rsp = json.loads(rsp_json)
200-
return rsp
224+
return self._transmit_and_receive(req)
201225

202226
@serial_lock
203227
def Reset(self):
@@ -232,7 +256,18 @@ def __init__(self, uart_id, debug=False):
232256
self._debug = debug
233257

234258
if use_serial_lock:
235-
self.lock = FileLock('serial.lock', timeout=1)
259+
self.lock = FileLock('serial.lock')
260+
else:
261+
self.lock = NoOpSerialLock()
262+
263+
if sys.implementation.name == 'micropython':
264+
self._read_byte = self._read_byte_micropython
265+
elif sys.implementation.name == 'cpython':
266+
self._read_byte = self._read_byte_cpython
267+
elif sys.implementation.name == 'circuitpython':
268+
self._read_byte = self._read_byte_circuitpython
269+
else:
270+
raise NotImplementedError(f'Unsupported platform: {sys.implementation.name}')
236271

237272
self.Reset()
238273

0 commit comments

Comments
 (0)