Skip to content

Commit 8a42fc5

Browse files
committed
Address review feedback.
1 parent 585ce82 commit 8a42fc5

1 file changed

Lines changed: 91 additions & 48 deletions

File tree

notecard/notecard.py

Lines changed: 91 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,19 @@
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 sys.platform == 'linux2'):
4744

48-
use_serial_lock = True
49-
from filelock import Timeout, FileLock
45+
use_periphery = True
46+
from periphery import I2C
47+
48+
use_serial_lock = True
49+
from filelock import FileLock
50+
from filelock import Timeout as SerialLockTimeout
51+
else:
52+
class SerialLockTimeout(Exception):
53+
"""A null SerialLockTimeout for when use_serial_lock is False."""
54+
55+
pass
5056

5157
use_i2c_lock = not use_periphery and sys.implementation.name != 'micropython'
5258

@@ -75,18 +81,35 @@ def _prepare_request(req, debug=False):
7581
return req_json
7682

7783

84+
class NullContextManager:
85+
"""A null context manager for use with NoOpSerialLock."""
86+
87+
def __enter__(self):
88+
"""Null enter function. Required for context managers."""
89+
pass
90+
91+
def __exit__(self, exc_type, exc_value, traceback):
92+
"""Null exit function. Required for context managers."""
93+
pass
94+
95+
96+
class NoOpSerialLock():
97+
"""A no-op serial lock class for when use_serial_lock is False."""
98+
99+
def acquire(*args, **kwargs):
100+
"""Acquire the no-op lock."""
101+
return NullContextManager()
102+
103+
78104
def serial_lock(fn):
79105
"""Attempt to get a lock on the serial channel used for Notecard comms."""
80106

81107
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)
108+
try:
109+
with self.lock.acquire(timeout=5):
110+
return fn(self, *args, **kwargs)
111+
except SerialLockTimeout:
112+
raise Exception('Notecard in use')
90113

91114
return decorator
92115

@@ -146,58 +169,67 @@ def SetTransactionPins(self, rtx_pin, ctx_pin):
146169
class OpenSerial(Notecard):
147170
"""Notecard class for Serial communication."""
148171

172+
@serial_lock
149173
def _transmit(self, req):
150174
req = self._preprocess_req(req)
151175
req_json = _prepare_request(req, self._debug)
152176

153-
transaction_timeout_secs = 30
154-
if self._transaction_manager:
155-
self._transaction_manager.start(transaction_timeout_secs)
177+
try:
178+
transaction_timeout_secs = 30
179+
if self._transaction_manager:
180+
self._transaction_manager.start(transaction_timeout_secs)
156181

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
182+
seg_off = 0
183+
seg_left = len(req_json)
184+
while seg_left > 0:
185+
seg_len = seg_left
186+
if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN:
187+
seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
163188

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)
189+
self.uart.write(req_json[seg_off:seg_off + seg_len].encode('utf-8'))
190+
seg_off += seg_len
191+
seg_left -= seg_len
192+
time.sleep(CARD_REQUEST_SEGMENT_DELAY_MS / 1000)
193+
finally:
194+
if self._transaction_manager:
195+
self._transaction_manager.stop()
168196

169-
if self._transaction_manager:
170-
self._transaction_manager.stop()
197+
@serial_lock
198+
def _transmit_and_receive(self, req):
199+
self._transmit(req)
171200

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
201+
rsp_json = self.uart.readline()
202+
if self._debug:
203+
print(rsp_json.rstrip())
204+
205+
return json.loads(rsp_json)
206+
207+
def _read_byte_micropython(self):
208+
"""Read a single byte from the Notecard (MicroPython)."""
209+
if not self.uart.any():
210+
return None
211+
return self.uart.read(1)
212+
213+
def _read_byte_cpython(self):
214+
"""Read a single byte from the Notecard (CPython)."""
215+
if self.uart.in_waiting == 0:
216+
return None
217+
return self.uart.read(1)
218+
219+
def _read_byte_circuitpython(self):
220+
"""Read a single byte from the Notecard (CircuitPython)."""
180221
return self.uart.read(1)
181222

182-
@serial_lock
183223
def Command(self, req):
184224
"""Send a command to the Notecard. The Notecard response is ignored."""
185225
if 'cmd' not in req:
186226
raise Exception("Please use 'cmd' instead of 'req'")
187227

188228
self._transmit(req)
189229

190-
@serial_lock
191230
def Transaction(self, req):
192231
"""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
232+
return self._transmit_and_receive(req)
201233

202234
@serial_lock
203235
def Reset(self):
@@ -232,7 +264,18 @@ def __init__(self, uart_id, debug=False):
232264
self._debug = debug
233265

234266
if use_serial_lock:
235-
self.lock = FileLock('serial.lock', timeout=1)
267+
self.lock = FileLock('serial.lock')
268+
else:
269+
self.lock = NoOpSerialLock()
270+
271+
if sys.implementation.name == 'micropython':
272+
self._read_byte = self._read_byte_micropython
273+
elif sys.implementation.name == 'cpython':
274+
self._read_byte = self._read_byte_cpython
275+
elif sys.implementation.name == 'circuitpython':
276+
self._read_byte = self._read_byte_circuitpython
277+
else:
278+
raise NotImplementedError(f'Unsupported platform: {sys.implementation.name}')
236279

237280
self.Reset()
238281

0 commit comments

Comments
 (0)