@@ -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
@@ -235,6 +252,11 @@ def close(self) -> None:
235
252
# Ensure logs have finished writing
236
253
self .log_thread .join ()
237
254
255
+ def close (self ) -> None :
256
+ self .cleanup ()
257
+ LED_CONTROLLER .set_status (LedStatus .NoUSB )
258
+ LED_CONTROLLER .set_code (False )
259
+
238
260
# Explicitly close handler before removing it
239
261
self .handler .close ()
240
262
USERCODE_LOGGER .removeHandler (self .handler )
@@ -266,7 +288,7 @@ def _watch_process(self) -> None:
266
288
time .sleep (1 - process_lifetime )
267
289
268
290
# Start clean-up
269
- self .close ()
291
+ self .cleanup ()
270
292
271
293
def _setup_logging (self , log_dir : str ) -> None :
272
294
self ._rotate_old_logs (log_dir )
@@ -296,9 +318,9 @@ def _log_output(self, pipe: IO[str]) -> None:
296
318
297
319
def _set_leds (self ) -> None :
298
320
if self .process .returncode == 0 :
299
- LED_CONTROLLER .green ( )
321
+ LED_CONTROLLER .set_status ( LedStatus . Finished )
300
322
else :
301
- LED_CONTROLLER .red ( )
323
+ LED_CONTROLLER .set_status ( LedStatus . Crashed )
302
324
303
325
def _rotate_old_logs (self , log_dir : str ) -> None :
304
326
"""
@@ -319,10 +341,12 @@ def _rotate_old_logs(self, log_dir: str) -> None:
319
341
320
342
class MetadataUSBHandler (USBHandler ):
321
343
def __init__ (self , mountpoint_path : str ) -> None :
322
- pass # Nothing to do.
344
+ # NOTE the comp LED just represents the presence of a comp mode USB
345
+ # not whether comp mode is enabled
346
+ LED_CONTROLLER .set_comp (True )
323
347
324
348
def close (self ) -> None :
325
- pass # Nothing to do.
349
+ LED_CONTROLLER . set_comp ( False )
326
350
327
351
328
352
class AutorunProcessRegistry (object ):
@@ -462,6 +486,7 @@ def main():
462
486
463
487
registry = AutorunProcessRegistry ()
464
488
489
+ LED_CONTROLLER .mark_start ()
465
490
# Initial pass (in case an autorun FS is already mounted)
466
491
registry .update_filesystems (fstab_reader .read ())
467
492
0 commit comments