123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #!/usr/bin/env python3
- #
- # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
- # Copyright (C)2013-2023 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 (Armbian)',
- status = '/sys/class/leds/orangepi:red:status/brightness',
- trigger = None,
- trigger_states = None ),
- 'rock_pi': binfo(
- name = 'Rock Pi (Armbian)',
- status = '/sys/class/leds/status/brightness',
- trigger = '/sys/class/leds/status/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 or simulate
- if not enabled:
- self.set = self.stop = self.noop
- return
- self.ev = threading.Event()
- self.led_thread = None
- for board_id,board in self.boards.items():
- if board_id == 'dummy' and not simulate:
- continue
- try: os.stat(board.status)
- except: pass
- else: break
- else:
- from .util import die
- die( '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'))
- def check_access(fn,desc,init_val=None):
- try:
- 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')
- return True
- except PermissionError:
- from .util import die
- die(2,'\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'))
- check_access(board.status,desc='status LED control')
- if board.trigger:
- check_access(board.trigger,desc='LED trigger',init_val=board.trigger_states[0])
- self.board = board
- @classmethod
- def create_dummy_control_files(cls):
- db = cls.boards['dummy']
- with open(db.status,'w') as fp:
- fp.write('0\n')
- with open(db.trigger,'w') as fp:
- fp.write(db.trigger_states[1]+'\n')
- @classmethod
- def delete_dummy_control_files(cls):
- db = cls.boards['dummy']
- os.unlink(db.status)
- os.unlink(db.trigger)
- def noop(self,*args,**kwargs): pass
- def ev_sleep(self,secs):
- self.ev.wait(secs)
- return self.ev.is_set()
- def led_loop(self,on_secs,off_secs):
- if self.debug:
- msg(f'led_loop({on_secs},{off_secs})')
- if not on_secs:
- with open(self.board.status,'w') as fp:
- fp.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)])
- with open(self.board.status,'w') as fp:
- fp.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:
- with open(self.board.trigger,'w') as fp:
- fp.write(self.board.trigger_states[1]+'\n')
|