Skip to content

Commit 6ba782d

Browse files
committed
Clean up serial comms code.
- Add a serial_lock decorator that can be used on functions that attempt to acquire a lock on the serial port. - Make serialReadByte, serialReset, serialCommand, and serialTransaction member functions of OpenSerial instead of being free functions. - Refactor serialCommand and serialTransaction (now renamed Command and Transaction, respectively) to unify common code in a new internal function, _transmit.
1 parent 93927f5 commit 6ba782d

File tree

1 file changed

+79
-127
lines changed

1 file changed

+79
-127
lines changed

notecard/notecard.py

Lines changed: 79 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -75,99 +75,20 @@ def _prepare_request(req, debug=False):
7575
return req_json
7676

7777

78-
def serialReadByte(port):
79-
"""Read a single byte from a Notecard."""
80-
if sys.implementation.name == 'micropython':
81-
if not port.any():
82-
return None
83-
elif sys.implementation.name == 'cpython':
84-
if port.in_waiting == 0:
85-
return None
86-
return port.read(1)
87-
88-
89-
def serialReset(port):
90-
"""Send a reset command to a Notecard."""
91-
for i in range(10):
92-
try:
93-
port.write(b'\n')
94-
except:
95-
continue
96-
time.sleep(0.5)
97-
somethingFound = False
98-
nonControlCharFound = False
99-
while True:
100-
data = serialReadByte(port)
101-
if (data is None) or (data == b''):
102-
break
103-
somethingFound = True
104-
if data[0] >= 0x20:
105-
nonControlCharFound = True
106-
if somethingFound and not nonControlCharFound:
107-
break
108-
else:
109-
raise Exception("Notecard not responding")
110-
111-
112-
def serialTransaction(port, req, debug, txn_manager=None):
113-
"""Perform a single write to and read from a Notecard."""
114-
req_json = _prepare_request(req, debug)
115-
116-
transaction_timeout_secs = 30
117-
if txn_manager:
118-
txn_manager.start(transaction_timeout_secs)
119-
120-
try:
121-
seg_off = 0
122-
seg_left = len(req_json)
123-
while True:
124-
seg_len = seg_left
125-
if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN:
126-
seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
127-
128-
port.write(req_json[seg_off:seg_off + seg_len].encode('utf-8'))
129-
seg_off += seg_len
130-
seg_left -= seg_len
131-
if seg_left == 0:
132-
break
133-
time.sleep(CARD_REQUEST_SEGMENT_DELAY_MS / 1000)
134-
finally:
135-
if txn_manager:
136-
txn_manager.stop()
137-
138-
rsp_json = port.readline()
139-
if debug:
140-
print(rsp_json.rstrip())
141-
142-
rsp = json.loads(rsp_json)
143-
return rsp
144-
145-
146-
def serialCommand(port, req, debug, txn_manager=None):
147-
"""Perform a single write to and read from a Notecard."""
148-
req_json = _prepare_request(req, debug)
149-
150-
transaction_timeout_secs = 30
151-
if txn_manager:
152-
txn_manager.start(transaction_timeout_secs)
78+
def serial_lock(fn):
79+
"""Attempt to get a lock on the serial channel used for Notecard comms."""
15380

154-
try:
155-
seg_off = 0
156-
seg_left = len(req_json)
157-
while True:
158-
seg_len = seg_left
159-
if seg_len > CARD_REQUEST_SEGMENT_MAX_LEN:
160-
seg_len = CARD_REQUEST_SEGMENT_MAX_LEN
81+
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)
16190

162-
port.write(req_json[seg_off:seg_off + seg_len].encode('utf-8'))
163-
seg_off += seg_len
164-
seg_left -= seg_len
165-
if seg_left == 0:
166-
break
167-
time.sleep(CARD_REQUEST_SEGMENT_DELAY_MS / 1000)
168-
finally:
169-
if txn_manager:
170-
txn_manager.stop()
91+
return decorator
17192

17293

17394
class Notecard:
@@ -225,51 +146,81 @@ def SetTransactionPins(self, rtx_pin, ctx_pin):
225146
class OpenSerial(Notecard):
226147
"""Notecard class for Serial communication."""
227148

228-
def Command(self, req):
229-
"""Perform a Notecard command and exit with no response."""
149+
def _transmit(self, req):
230150
req = self._preprocess_req(req)
151+
req_json = _prepare_request(req, self._debug)
152+
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
163+
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)
168+
169+
if self._transaction_manager:
170+
self._transaction_manager.stop()
171+
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
180+
return self.uart.read(1)
181+
182+
@serial_lock
183+
def Command(self, req):
184+
"""Send a command to the Notecard. The Notecard response is ignored."""
231185
if 'cmd' not in req:
232186
raise Exception("Please use 'cmd' instead of 'req'")
233187

234-
if use_serial_lock:
235-
try:
236-
self.lock.acquire(timeout=5)
237-
serialCommand(self.uart, req, self._debug, self._transaction_manager)
238-
except Timeout:
239-
raise Exception("Notecard in use")
240-
finally:
241-
self.lock.release()
242-
else:
243-
serialCommand(self.uart, req, self._debug, self._transaction_manager)
188+
self._transmit(req)
244189

190+
@serial_lock
245191
def Transaction(self, req):
246192
"""Perform a Notecard transaction and return the result."""
247-
req = self._preprocess_req(req)
248-
if use_serial_lock:
249-
try:
250-
self.lock.acquire(timeout=5)
251-
return serialTransaction(self.uart, req, self._debug,
252-
self._transaction_manager)
253-
except Timeout:
254-
raise Exception("Notecard in use")
255-
finally:
256-
self.lock.release()
257-
else:
258-
return serialTransaction(self.uart, req, self._debug,
259-
self._transaction_manager)
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
260201

202+
@serial_lock
261203
def Reset(self):
262204
"""Reset the Notecard."""
263-
if use_serial_lock:
205+
for i in range(10):
264206
try:
265-
self.lock.acquire(timeout=5)
266-
serialReset(self.uart)
267-
except Timeout:
268-
raise Exception("Notecard in use")
269-
finally:
270-
self.lock.release()
271-
else:
272-
serialReset(self.uart)
207+
self.uart.write(b'\n')
208+
except:
209+
continue
210+
time.sleep(0.5)
211+
somethingFound = False
212+
nonControlCharFound = False
213+
while True:
214+
data = self._read_byte()
215+
if (data is None) or (data == b''):
216+
break
217+
somethingFound = True
218+
if data[0] >= 0x20:
219+
nonControlCharFound = True
220+
if somethingFound and not nonControlCharFound:
221+
break
222+
else:
223+
raise Exception('Notecard not responding')
273224

274225
def __init__(self, uart_id, debug=False):
275226
"""Initialize the Notecard before a reset."""
@@ -380,11 +331,11 @@ def _receive(self, timeout_secs, chunk_delay_secs, wait_for_newline):
380331
return read_data
381332

382333
def Command(self, req):
383-
"""Perform a Notecard command and return with no response."""
334+
"""Perform a Notecard command and exit with no response."""
335+
req = self._preprocess_req(req)
384336
if 'cmd' not in req:
385337
raise Exception("Please use 'cmd' instead of 'req'")
386338

387-
req = self._preprocess_req(req)
388339
req_json = _prepare_request(req, self._debug)
389340

390341
while not self.lock():
@@ -404,6 +355,7 @@ def Command(self, req):
404355
def Transaction(self, req):
405356
"""Perform a Notecard transaction and return the result."""
406357
req = self._preprocess_req(req)
358+
407359
req_json = _prepare_request(req, self._debug)
408360
rsp_json = ""
409361

0 commit comments

Comments
 (0)