@@ -86,12 +86,24 @@ class Mountpoint(NamedTuple):
86
86
)
87
87
88
88
89
+ class LedStatus (Enum ):
90
+ NoUSB = (False , False , False ) # Off
91
+ Running = (False , False , True ) # Blue
92
+ Killed = (True , False , True ) # Magenta
93
+ Finished = (False , True , False ) # Green
94
+ Crashed = (True , False , False ) # Red
95
+
96
+
89
97
class LEDController ():
90
98
@unique
91
99
class LEDs (IntEnum ):
92
- RED = 2
93
- YELLOW = 3
94
- GREEN = 4
100
+ BOOT_100 = 13
101
+ CODE = 11
102
+ COMP = 16
103
+ WIFI = 8
104
+ STATUS_RED = 26
105
+ STATUS_GREEN = 20
106
+ STATUS_BLUE = 21
95
107
96
108
def __init__ (self ) -> None :
97
109
if IS_PI :
@@ -100,23 +112,27 @@ def __init__(self) -> None:
100
112
GPIO .setmode (GPIO .BCM )
101
113
GPIO .setup ([led .value for led in self .LEDs ], GPIO .OUT , initial = GPIO .LOW )
102
114
103
- def red (self ) -> None :
115
+ def mark_start (self ) -> None :
104
116
if IS_PI :
105
- GPIO .output (self .LEDs .RED , GPIO .HIGH )
106
- GPIO .output (self .LEDs .YELLOW , GPIO .LOW )
107
- GPIO .output (self .LEDs .GREEN , GPIO .LOW )
117
+ GPIO .output (self .LEDs .BOOT_100 , GPIO .HIGH )
108
118
109
- def yellow (self ) -> None :
119
+ def set_comp (self , value : bool ) -> None :
110
120
if IS_PI :
111
- GPIO .output (self .LEDs .RED , GPIO .LOW )
112
- GPIO .output (self .LEDs .YELLOW , GPIO .HIGH )
113
- GPIO .output (self .LEDs .GREEN , GPIO .LOW )
121
+ GPIO .output (self .LEDs .COMP , GPIO .HIGH if value else GPIO .LOW )
114
122
115
- def green (self ) -> None :
123
+ def set_code (self , value : bool ) -> None :
116
124
if IS_PI :
117
- GPIO .output (self .LEDs .RED , GPIO .LOW )
118
- GPIO .output (self .LEDs .YELLOW , GPIO .LOW )
119
- GPIO .output (self .LEDs .GREEN , GPIO .HIGH )
125
+ GPIO .output (self .LEDs .CODE , GPIO .HIGH if value else GPIO .LOW )
126
+
127
+ def set_wifi (self , value : bool ) -> None :
128
+ if IS_PI :
129
+ GPIO .output (self .LEDs .WIFI , GPIO .HIGH if value else GPIO .LOW )
130
+
131
+ def set_status (self , value : LedStatus ) -> None :
132
+ if IS_PI :
133
+ GPIO .output (self .LEDs .STATUS_RED , GPIO .HIGH if value .value [0 ] else GPIO .LOW )
134
+ GPIO .output (self .LEDs .STATUS_GREEN , GPIO .HIGH if value .value [1 ] else GPIO .LOW )
135
+ GPIO .output (self .LEDs .STATUS_BLUE , GPIO .HIGH if value .value [2 ] else GPIO .LOW )
120
136
121
137
122
138
LED_CONTROLLER = LEDController ()
@@ -198,7 +214,8 @@ def close(self) -> None:
198
214
class RobotUSBHandler (USBHandler ):
199
215
def __init__ (self , mountpoint_path : str ) -> None :
200
216
self ._setup_logging (mountpoint_path )
201
- LED_CONTROLLER .yellow ()
217
+ LED_CONTROLLER .set_code (True )
218
+ LED_CONTROLLER .set_status (LedStatus .Running )
202
219
env = dict (os .environ )
203
220
env ["SBOT_METADATA_PATH" ] = MOUNTPOINT_DIR
204
221
if MQTT_URL is not None :
@@ -223,7 +240,7 @@ def __init__(self, mountpoint_path: str) -> None:
223
240
target = self ._log_output , args = (self .process .stdout ,))
224
241
self .log_thread .start ()
225
242
226
- def close (self ) -> None :
243
+ def cleanup (self ) -> None :
227
244
self ._send_signal (signal .SIGTERM )
228
245
try :
229
246
# Wait for the process to exit
@@ -232,6 +249,11 @@ def close(self) -> None:
232
249
# The process did not exit after 5 seconds, so kill it.
233
250
self ._send_signal (signal .SIGKILL )
234
251
self ._set_leds ()
252
+
253
+ def close (self ) -> None :
254
+ self .cleanup ()
255
+ LED_CONTROLLER .set_status (LedStatus .NoUSB )
256
+ LED_CONTROLLER .set_code (False )
235
257
USERCODE_LOGGER .removeHandler (self .handler )
236
258
237
259
def _send_signal (self , sig : int ) -> None :
@@ -256,7 +278,7 @@ def _watch_process(self) -> None:
256
278
time .sleep (1 - process_lifetime )
257
279
258
280
# Start clean-up
259
- self .close ()
281
+ self .cleanup ()
260
282
261
283
def _setup_logging (self , log_dir : str ) -> None :
262
284
self ._rotate_old_logs (log_dir )
@@ -286,9 +308,9 @@ def _log_output(self, pipe: IO[str]) -> None:
286
308
287
309
def _set_leds (self ) -> None :
288
310
if self .process .returncode == 0 :
289
- LED_CONTROLLER .green ( )
311
+ LED_CONTROLLER .set_status ( LedStatus . Finished )
290
312
else :
291
- LED_CONTROLLER .red ( )
313
+ LED_CONTROLLER .set_status ( LedStatus . Crashed )
292
314
293
315
def _rotate_old_logs (self , log_dir : str ) -> None :
294
316
"""
@@ -309,10 +331,12 @@ def _rotate_old_logs(self, log_dir: str) -> None:
309
331
310
332
class MetadataUSBHandler (USBHandler ):
311
333
def __init__ (self , mountpoint_path : str ) -> None :
312
- pass # Nothing to do.
334
+ # NOTE the comp LED just represents the presence of a comp mode USB
335
+ # not whether comp mode is enabled
336
+ LED_CONTROLLER .set_comp (True )
313
337
314
338
def close (self ) -> None :
315
- pass # Nothing to do.
339
+ LED_CONTROLLER . set_comp ( False )
316
340
317
341
318
342
class AutorunProcessRegistry (object ):
@@ -452,6 +476,7 @@ def main():
452
476
453
477
registry = AutorunProcessRegistry ()
454
478
479
+ LED_CONTROLLER .mark_start ()
455
480
# Initial pass (in case an autorun FS is already mounted)
456
481
registry .update_filesystems (fstab_reader .read ())
457
482
0 commit comments