led.py: improve initialization logic, add interactive test

This commit is contained in:
The MMGen Project 2025-01-21 09:36:14 +00:00
commit fb17a3b2c9
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 107 additions and 30 deletions

View file

@ -80,47 +80,67 @@ class LEDControl:
continue
try:
os.stat(board.control)
except:
pass
else:
break
except FileNotFoundError:
pass
else:
die('NoLEDSupport', 'Control files not found! LED control not supported on this system')
msg(f'{board.name} board detected')
if self.debug:
msg(f'\n Control file: {board.control}\n Trigger file: {board.trigger}')
msg(f'\n Status file: {board.control}\n Trigger file: {board.trigger}')
def check_access(fn, desc, init_val=None):
def write_init_val(fn, init_val):
if not init_val:
with open(fn) as fp:
init_val = fp.read().strip()
with open(fn, 'w') as fp:
fp.write(f'{init_val}\n')
def write_init_val(init_val):
if not init_val:
with open(fn) as fp:
init_val = fp.read().strip()
with open(fn, 'w') as fp:
fp.write(f'{init_val}\n')
def permission_error_action(fn, desc):
cmd = f'sudo chmod 0666 {fn}'
if have_sudo():
msg(orange(f'Running ‘{cmd}'))
run(cmd.split(), check=True)
else:
msg('\n{}\n{}\n{}'.format(
blue(f'You do not have write access to the {desc}'),
blue(f'To allow access, run the following command:\n\n {cmd}'),
orange('[To prevent this message in the future, enable sudo without a password]')
))
sys.exit(1)
def init_state(fn, desc, init_val=None):
try:
write_init_val(init_val)
write_init_val(fn, init_val)
except PermissionError:
cmd = f'sudo chmod 0666 {fn}'
if have_sudo():
msg(orange(f'Running ‘{cmd}'))
run(cmd.split(), check=True)
write_init_val(init_val)
else:
msg('\n{}\n{}\n{}'.format(
blue(f'You do not have access to the {desc} file'),
blue(f'To allow access, run the following command:\n\n {cmd}'),
orange('[To prevent this message in the future, enable sudo without a password]')
))
sys.exit(1)
check_access(board.control, desc='status LED control')
permission_error_action(fn, desc)
write_init_val(fn, init_val)
# Writing to control file can alter trigger file, so read and initialize trigger file first:
if board.trigger:
check_access(board.trigger, desc='LED trigger', init_val=board.trigger_states[0])
def get_cur_state():
try:
with open(board.trigger) as fh:
states = fh.read()
except PermissionError:
permission_error_action(board.trigger, 'status LED trigger file')
with open(board.trigger) as fh:
states = fh.read()
res = [a for a in states.split() if a.startswith('[') and a.endswith(']')]
return res[0][1:-1] if len(res) == 1 else None
if cur_state := get_cur_state():
msg(f'Saving current LED trigger state: [{cur_state}]')
board.trigger_reset = cur_state
else:
msg('Unable to determine current LED trigger state')
init_state(board.trigger, desc='status LED trigger file', init_val=board.trigger_disable)
init_state(board.control, desc='status LED control file')
self.board = board

57
test/misc/led.py Executable file
View file

@ -0,0 +1,57 @@
#!/usr/bin/env python3
import sys, os, atexit
pn = os.path.abspath(os.path.dirname(sys.argv[0]))
parpar = os.path.dirname(os.path.dirname(pn))
os.chdir(parpar)
sys.path[0] = os.curdir
from mmgen.cfg import Config
from mmgen.util import msg
from mmgen.ui import keypress_confirm
from mmgen.led import LEDControl
opts_data = {
'text': {
'desc': 'Interactively test LED functionality',
'usage': 'command',
'options': """
-h, --help Print this help message
""",
}
}
cfg = Config(opts_data=opts_data)
def confirm_or_exit(prompt):
if not keypress_confirm(cfg, f'{prompt}. OK?', default_yes=True):
msg('Exiting at user request')
sys.exit(1)
confirm_or_exit('This script will interactively test LED functionality')
led = LEDControl(enabled=True)
atexit.register(led.stop)
confirm_or_exit('LED should now be turned off')
led.set('busy')
confirm_or_exit('LED should now be signaling busy (rapid flashing)')
led.set('standby')
confirm_or_exit('LED should now be signaling standby (slow flashing)')
led.set('error')
confirm_or_exit('LED should now be signaling error (insistent flashing)')
led.set('off')
confirm_or_exit('LED should now be turned off')
led.stop()
confirm_or_exit(f'LED should now be in its original state [trigger={led.board.trigger_reset}]')