Skip to content

Commit a87bda1

Browse files
committed
monitor: Main modules formatted with black.
1 parent 63d818a commit a87bda1

File tree

3 files changed

+64
-36
lines changed

3 files changed

+64
-36
lines changed

v3/as_demos/monitor/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ The decorator positional args are as follows:
122122
[Pico Pin mapping](./README.md#3-pico-pin-mapping).
123123
2. `max_instances=1` Defines the maximum number of concurrent instances of the
124124
task to be independently monitored (default 1).
125+
3. `verbose=True` If `False` suppress the warning which is printed on the host
126+
if the instance count exceeds `max_instances`.
125127

126128
Whenever the coroutine runs, a pin on the Pico will go high, and when the code
127129
terminates it will go low. This enables the behaviour of the system to be

v3/as_demos/monitor/monitor.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,43 @@ def _quit(s):
1414
print("Monitor " + s)
1515
exit(0)
1616

17-
_write = lambda _ : _quit("must run set_device")
18-
_dummy = lambda : None # If UART do nothing.
17+
18+
_write = lambda _: _quit("must run set_device")
19+
_ifrst = lambda: None # Reset interface. If UART do nothing.
1920

2021
# For UART pass initialised UART. Baudrate must be 1_000_000.
2122
# For SPI pass initialised instance SPI. Can be any baudrate, but
2223
# must be default in other respects.
2324
def set_device(dev, cspin=None):
2425
global _write
25-
global _dummy
26+
global _ifrst
2627
if isinstance(dev, UART) and cspin is None: # UART
2728
_write = dev.write
2829
elif isinstance(dev, SPI) and isinstance(cspin, Pin):
2930
cspin(1)
31+
3032
def spiwrite(data):
3133
cspin(0)
3234
dev.write(data)
3335
cspin(1)
36+
3437
_write = spiwrite
38+
3539
def clear_sm(): # Set Pico SM to its initial state
3640
cspin(1)
3741
dev.write(b"\0") # SM is now waiting for CS low.
38-
_dummy = clear_sm
42+
43+
_ifrst = clear_sm
3944
else:
4045
_quit("set_device: invalid args.")
4146

47+
4248
# Justification for validation even when decorating a method
4349
# /mnt/qnap2/data/Projects/Python/AssortedTechniques/decorators
4450
_available = set(range(0, 22)) # Valid idents are 0..21
4551
_reserved = set() # Idents reserved for synchronous monitoring
4652

53+
4754
def _validate(ident, num=1):
4855
if ident >= 0 and ident + num < 22:
4956
try:
@@ -54,83 +61,90 @@ def _validate(ident, num=1):
5461
else:
5562
_quit("error - ident {:02d} out of range.".format(ident))
5663

64+
5765
# Reserve ID's to be used for synchronous monitoring
5866
def reserve(*ids):
5967
for ident in ids:
6068
_validate(ident)
6169
_reserved.add(ident)
6270

71+
6372
# Check whether a synchronous ident was reserved
6473
def _check(ident):
6574
if ident not in _reserved:
6675
_quit("error: synchronous ident {:02d} was not reserved.".format(ident))
6776

77+
6878
# asynchronous monitor
69-
def asyn(n, max_instances=1):
79+
def asyn(n, max_instances=1, verbose=True):
7080
def decorator(coro):
71-
# This code runs before asyncio.run()
7281
_validate(n, max_instances)
7382
instance = 0
83+
7484
async def wrapped_coro(*args, **kwargs):
75-
# realtime
7685
nonlocal instance
7786
d = 0x40 + n + min(instance, max_instances - 1)
7887
v = int.to_bytes(d, 1, "big")
7988
instance += 1
80-
if instance > max_instances: # Warning only
81-
print("Monitor {:02d} max_instances reached.".format(n))
89+
if verbose and instance > max_instances: # Warning only.
90+
print("Monitor ident: {:02d} instances: {}.".format(n, instance))
8291
_write(v)
8392
try:
8493
res = await coro(*args, **kwargs)
8594
except asyncio.CancelledError:
86-
raise
95+
raise # Other exceptions produce traceback.
8796
finally:
8897
d |= 0x20
8998
v = int.to_bytes(d, 1, "big")
9099
_write(v)
91100
instance -= 1
92101
return res
102+
93103
return wrapped_coro
104+
94105
return decorator
95106

107+
96108
# If SPI, clears the state machine in case prior test resulted in the DUT
97109
# crashing. It does this by sending a byte with CS\ False (high).
98110
def init():
99-
_dummy() # Does nothing if UART
111+
_ifrst() # Reset interface. Does nothing if UART.
100112
_write(b"z") # Clear Pico's instance counters etc.
101113

114+
102115
# Optionally run this to show up periods of blocking behaviour
103-
async def hog_detect(i=1, s=(b"\x40", b"\x60")):
116+
async def hog_detect(s=(b"\x40", b"\x60")):
104117
while True:
105-
_write(s[(i := i ^ 1)])
106-
await asyncio.sleep_ms(0)
118+
for v in s:
119+
_write(v)
120+
await asyncio.sleep_ms(0)
121+
107122

108123
# Monitor a synchronous function definition
109124
def sync(n):
110125
def decorator(func):
111126
_validate(n)
112-
dstart = 0x40 + n
113-
vstart = int.to_bytes(dstart, 1, "big")
114-
dend = 0x60 + n
115-
vend = int.to_bytes(dend, 1, "big")
127+
vstart = int.to_bytes(0x40 + n, 1, "big")
128+
vend = int.to_bytes(0x60 + n, 1, "big")
129+
116130
def wrapped_func(*args, **kwargs):
117131
_write(vstart)
118132
res = func(*args, **kwargs)
119133
_write(vend)
120134
return res
135+
121136
return wrapped_func
137+
122138
return decorator
123139

140+
124141
# Runtime monitoring: can't validate because code may be looping.
125142
# Monitor a synchronous function call
126143
class mon_call:
127144
def __init__(self, n):
128145
_check(n)
129-
self.n = n
130-
self.dstart = 0x40 + n
131-
self.vstart = int.to_bytes(self.dstart, 1, "big")
132-
self.dend = 0x60 + n
133-
self.vend = int.to_bytes(self.dend, 1, "big")
146+
self.vstart = int.to_bytes(0x40 + n, 1, "big")
147+
self.vend = int.to_bytes(0x60 + n, 1, "big")
134148

135149
def __enter__(self):
136150
_write(self.vstart)
@@ -140,6 +154,7 @@ def __exit__(self, type, value, traceback):
140154
_write(self.vend)
141155
return False # Don't silence exceptions
142156

157+
143158
# Cause pico ident n to produce a brief (~80μs) pulse
144159
def trigger(n):
145160
_check(n)

v3/as_demos/monitor/monitor_pico.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,23 @@ def spi_in():
3535

3636

3737
class PIOSPI:
38-
3938
def __init__(self):
40-
self._sm = rp2.StateMachine(0, spi_in,
41-
in_shiftdir=rp2.PIO.SHIFT_LEFT,
42-
push_thresh=8, in_base=Pin(0),
43-
jmp_pin=Pin(2, Pin.IN, Pin.PULL_UP))
39+
self._sm = rp2.StateMachine(
40+
0,
41+
spi_in,
42+
in_shiftdir=rp2.PIO.SHIFT_LEFT,
43+
push_thresh=8,
44+
in_base=Pin(0),
45+
jmp_pin=Pin(2, Pin.IN, Pin.PULL_UP),
46+
)
4447
self._sm.active(1)
4548

4649
# Blocking read of 1 char. Returns ord(ch). If DUT crashes, worst case
4750
# is where CS is left low. SM will hang until user restarts. On restart
4851
# the app
4952
def read(self):
50-
return self._sm.get() & 0xff
53+
return self._sm.get() & 0xFF
54+
5155

5256
# ****** Define pins ******
5357

@@ -64,11 +68,14 @@ def read(self):
6468
# ****** Timing *****
6569

6670
pin_t = Pin(28, Pin.OUT)
71+
72+
6773
def _cb(_):
6874
pin_t(1)
6975
print("Timeout.")
7076
pin_t(0)
7177

78+
7279
tim = Timer()
7380

7481
# ****** Monitor ******
@@ -83,38 +90,42 @@ def _cb(_):
8390

8491
# native reduced latency to 10μs but killed the hog detector: timer never timed out.
8592
# Also locked up Pico so ctrl-c did not interrupt.
86-
#@micropython.native
93+
# @micropython.native
8794
def run(period=100, verbose=(), device="uart", vb=True):
8895
if isinstance(period, int):
8996
t_ms = period
9097
mode = SOON
9198
else:
9299
t_ms, mode = period
93100
if mode not in (SOON, LATE, MAX):
94-
raise ValueError('Invalid mode.')
101+
raise ValueError("Invalid mode.")
95102
for x in verbose:
96103
pins[x][2] = True
97104
# A device must support a blocking read.
98105
if device == "uart":
99106
uart = UART(0, 1_000_000) # rx on GPIO 1
107+
100108
def read():
101109
while not uart.any(): # Prevent UART timeouts
102110
pass
103111
return ord(uart.read(1))
112+
104113
elif device == "spi":
105114
pio = PIOSPI()
115+
106116
def read():
107117
return pio.read()
118+
108119
else:
109120
raise ValueError("Unsupported device:", device)
110121

111-
vb and print('Awaiting communication')
122+
vb and print("Awaiting communication.")
112123
h_max = 0 # Max hog duration (ms)
113124
h_start = 0 # Absolute hog start time
114125
while True:
115126
if x := read(): # Get an initial 0 on UART
116-
if x == 0x7a: # Init: program under test has restarted
117-
vb and print('Got communication.')
127+
if x == 0x7A: # Init: program under test has restarted
128+
vb and print("Got communication.")
118129
h_max = 0 # Restart timing
119130
h_start = 0
120131
for pin in pins:
@@ -140,7 +151,7 @@ def read():
140151
pin_t(1)
141152
pin_t(0)
142153
h_start = t
143-
p = pins[x & 0x1f] # Key: 0x40 (ord('@')) is pin ID 0
154+
p = pins[x & 0x1F] # Key: 0x40 (ord('@')) is pin ID 0
144155
if x & 0x20: # Going down
145156
p[1] -= 1
146157
if not p[1]: # Instance count is zero
@@ -149,4 +160,4 @@ def read():
149160
p[0](1)
150161
p[1] += 1
151162
if p[2]:
152-
print(f'ident {i} count {p[1]}')
163+
print(f"ident {i} count {p[1]}")

0 commit comments

Comments
 (0)