Skip to content

Commit

Permalink
new LEDControl class
Browse files Browse the repository at this point in the history
  • Loading branch information
mmgen committed May 10, 2020
1 parent 78a199c commit 5ba2f51
Showing 1 changed file with 184 additions and 0 deletions.
184 changes: 184 additions & 0 deletions mmgen/led.py
@@ -0,0 +1,184 @@
#!/usr/bin/env python3
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
led: Control the LED on a single-board computer
"""

import sys,time
from mmgen.common import *
import threading

class LEDControl:

binfo = namedtuple('board_info',['name','status','trigger','trigger_states'])
boards = {
'raspi_pi': binfo(
name = 'Raspberry Pi',
status = '/sys/class/leds/led0/brightness',
trigger = '/sys/class/leds/led0/trigger',
trigger_states = ('none','mmc0') ),
'orange_pi': binfo(
name = 'Orange Pi',
status = '/sys/class/leds/orangepi:red:status/brightness',
trigger = None,
trigger_states = None ),
# 'rock_pi': binfo( # TODO
# name = 'Rock Pi',
# status = '/sys/class/leds/user-led1/brightness',
# trigger = '/sys/class/leds/user-led1/trigger',
# trigger_states = ('none','heartbeat') ),
'dummy': binfo(
name = 'Fake',
status = '/tmp/led_status',
trigger = '/tmp/led_trigger',
trigger_states = ('none','original_value') ),
}

def __init__(self,enabled,simulate=False,debug=False):

self.enabled = enabled
self.debug = debug

if not enabled:
self.set = self.stop = self.noop
return

self.ev = threading.Event()
self.led_thread = None

if simulate:
type(self).create_dummy_control_files()
self.debug = True

for board_id,board in self.boards.items():
try: os.stat(board.status)
except: pass
else: break
else:
from mmgen.exception import NoLEDSupport
raise NoLEDSupport('Control files not found! LED control not supported on this system')

msg(f'{board.name} board detected')

if self.debug:
msg(fmt(f"""
Status file: {board.status}
Trigger file: {board.trigger}
""",indent=' ',strip_char='\t'))

if board_id == 'dummy' and not simulate:
if g.test_suite:
msg('Warning: no simulation requested but dummy LED control files detected')
self.debug = True
else:
die(1,fmt(f"""
No simulation requested but dummy LED control files detected:
{board.status}
{board.trigger}
You may wish to remove them and restart
""",indent=' ',strip_char='\t'))

def check_access(fn,desc,init_val=None):
try:
iv = init_val or open(fn).read().strip()
open(fn,'w').write(f'{iv}\n')
return True
except:
msg('\n'+fmt(f"""
You do not have access to the {desc} file
To allow access, run the following command:
sudo chmod 0666 {fn}
""",indent=' ',strip_char='\t'))
return False

if not check_access(board.status,desc='status LED control'):
sys.exit(1)

if board.trigger:
if not check_access(board.trigger,desc='LED trigger',init_val=board.trigger_states[0]):
sys.exit(1)

self.board = board

@classmethod
def create_dummy_control_files(cls):
db = cls.boards['dummy']
open(db.status,'w').write('0\n')
open(db.trigger,'w').write(db.trigger_states[1]+'\n')

def noop(self,*args,**kwargs): pass

def ev_sleep(self,secs):
self.ev.wait(secs)
return self.ev.isSet()

def led_loop(self,on_secs,off_secs):

if self.debug:
msg(f'led_loop({on_secs},{off_secs})')

if not on_secs:
open(self.board.status,'w').write('0\n')
while True:
if self.ev_sleep(3600):
return

while True:
for s_time,val in ((on_secs,255),(off_secs,0)):
if self.debug:
msg_r(('^','+')[bool(val)])
open(self.board.status,'w').write(f'{val}\n')
if self.ev_sleep(s_time):
if self.debug:
msg('\n')
return

def set(self,state):
lt = namedtuple('led_timings',['on_secs','off_secs'])
timings = {
'off': lt( 0, 0 ),
'standby': lt( 2.2, 0.2 ),
'busy': lt( 0.06, 0.06 ),
'error': lt( 0.5, 0.5 ) }

if self.led_thread:
self.ev.set()
self.led_thread.join()
self.ev.clear()

if self.debug:
msg(f'Setting LED state to {state!r}')

self.led_thread = threading.Thread(target=self.led_loop,name='LED loop',args=timings[state])
self.led_thread.start()

def stop(self):

self.set('off')
self.ev.set()
self.led_thread.join()

if self.debug:
msg('Stopping LED')

if self.board.trigger:
open(self.board.trigger,'w').write(self.board.trigger_states[1]+'\n')

0 comments on commit 5ba2f51

Please sign in to comment.