├── devicetree └── readme.txt ├── readme.txt ├── input ├── readme.txt └── evdevlist.py └── power ├── readme.txt ├── powerstatus.py ├── safe_shutdown.py └── daemon.py /devicetree/readme.txt: -------------------------------------------------------------------------------- 1 | Some devicetree overlay examples, mostly adapted from http://hipstercircuits.com 2 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Snippets of useful operations found out while tinkering with Beaglebone Black 2 | 3 | Such as: 4 | > PMIC / Power Management IC status reading via i2c including if its on USB,wall power, charging, etc 5 | 6 | > use pyevdev to query input devices for capabilities (not just beagle-specific) 7 | -------------------------------------------------------------------------------- /input/readme.txt: -------------------------------------------------------------------------------- 1 | beagle with Linux uses the event-driven device input system. 2 | things like joysticks show up in /dev/input/event0, etc 3 | we can use python and the pyevdev library to easily query them. 4 | 5 | python evdevlist.py will query all input devices and print out their capabilities. 6 | This should work on any modern Linux system not just Beagle. 7 | 8 | 9 | Below is sample output showing the default event0 which is the power button from the PMIC 10 | 11 | /dev/input/event0 tps65217_pwr_but 12 | Event types [('EV_KEY', 1L), ('EV_SYN', 0L)]: 13 | 1 Buttons: 14 | 0: ('KEY_POWER', 116L) 15 | 0 Relative Axes: 16 | 0 Absolute Axes: 17 | 0 Misc Events: 18 | [] 19 | 6 Sync Events: 20 | [('SYN_REPORT', 0L), ('SYN_CONFIG', 1L), ('?', 761L), ('?', 762L), ('?', 764L), ('?', 765L)] 21 | 0 Forcefeedback capabilities: 22 | [] 23 | HID LEDs: [] 24 | -------------------------------------------------------------------------------- /input/evdevlist.py: -------------------------------------------------------------------------------- 1 | # Use pyevdev to query the /dev/input/event* devices and see what they support 2 | # a helpful way to make sense of which one is which 3 | # 4 | # easy_install pyevdev 5 | # 6 | 7 | from evdev import InputDevice, list_devices,ecodes 8 | devices = map(InputDevice, list_devices()) 9 | 10 | # print an entry with its index 11 | # useful for buttons and axis where we think of them as 0-based 12 | def printlist(lst): 13 | for idx,val in enumerate(lst): 14 | print "\t\t%d: %s"%(idx,val) 15 | 16 | print 17 | print "Look for /dev/input/event* devices:" 18 | for dev in devices: 19 | print "="*40 20 | print( '%-20s %-32s %s' % (dev.fn, dev.name, dev.phys) ) 21 | capav =dev.capabilities(True,True) 22 | capa =dev.capabilities(False,False) 23 | 24 | print "\tEvent types %s: "%(capav.keys()) # EV_KEY, EV_ABS, etc 25 | 26 | print "\t%d Buttons:"%len(capa.get(ecodes.EV_KEY,[])) 27 | printlist(capav.get(('EV_KEY', 1L),[])) 28 | 29 | print "\t%d Relative Axes:"%len(capa.get(ecodes.EV_REL,[])) 30 | printlist(capav.get(('EV_REL', 2L),[])) 31 | 32 | print "\t%d Absolute Axes:"%len(capa.get(ecodes.EV_ABS,[])) 33 | printlist(capav.get(('EV_ABS', 3L),[])) 34 | 35 | print "\t%d Misc Events:"%len(capa.get(ecodes.EV_MSC,[])) 36 | print "\t\t%s"%capav.get(('EV_MSC', 4L),[]) 37 | 38 | print "\t%d Sync Events:"%len(capa.get(ecodes.EV_SYN,[])) 39 | print "\t\t%s"%capav.get(('EV_SYN', 0L),[]) 40 | 41 | print "\t%d Forcefeedback capabilities:"%len(capa.get(ecodes.EV_FF,[])) 42 | print "\t\t%s"%capav.get(('EV_FF', 21L),[]) 43 | 44 | print "\tHID LEDs: %s"%dev.leds(verbose=True) 45 | print 46 | 47 | -------------------------------------------------------------------------------- /power/readme.txt: -------------------------------------------------------------------------------- 1 | Beaglebone Black power management IC 2 | 3 | TI TPS65217 http://www.ti.com/product/tps65217C 4 | 5 | The chip on board the BBB has an I2C interface that tells us stuff about how it is being powered and if it is charging a battery. 6 | 7 | [Using a battery] 8 | Note that when hooking up a LiPo battery (such as the thin ones from Sparkfun) you must make all the connections to enable charging: 9 | 10 | TP5/BAT => Battery+ 11 | TP6/SENSE=> BAT pin on PCB 12 | TP7/TS => 10K NTC thermistor to ground. Or perhaps a 10K resistor to fool it. 13 | TP8/GND => Battery- 14 | 15 | [Safe shutdown] 16 | You can treat the battery like a UPS - when we detect we are on battery-only for too long, issue a safe linux shutdown command to prevent file system corruption. 17 | See safe_shutdown.py for an example that can be used as a Linux daemon to run on startup. 18 | 19 | [Reading the PMIC] 20 | PMIC is on I2C-0 address 0x24 21 | Easy to get started: use i2cget from the shell to query specific registers. 22 | The specific register addresses and their meanings are in the datasheet. 23 | 24 | Example: get the STATUS (0xA) register which tells us which power inputs (USB, AC) are active. 25 | If neither are true then we must be on battery! 26 | 27 | i2cget -y -f 0 0x24 0xA 28 | 29 | powerstatus.py uses this easy shell cmd to query a couple useful regs and print the results 30 | 31 | Sample output of powerstatus.py for an AC powered beagle with no battery: 32 | 33 | Querying Beaglebone Black Power Management IC on i2c-0 device 0x24 34 | On battery power only? 0 35 | 36 | Charging Battery? 0 37 | 38 | 39 | STATUS: r[0xa]=0x88 40 | 41 | Push Button = 0 42 | USB Power = 0 43 | AC Power = 1 44 | 45 | 46 | CHARGER: r[0x3]=0x1 47 | 48 | Temp sense error = 1 49 | Pre-charge Timedout = 0 50 | Charge Timedout = 0 51 | Active (charging) = 0 52 | Charge Termination Current = 0 53 | Thermal Suspend = 0 54 | DPPM Reduction = 0 55 | Thermal Regulation = 0 56 | 57 | 58 | PGOOD: r[0xc]=0x7f 59 | 60 | LDO2 power-good = 1 61 | LDO1 power-good = 1 62 | DCDC3 power-good = 1 63 | DCDC2 power-good = 1 64 | DCDC1 power-good = 1 65 | LDO4 power-good = 1 66 | LDO3 power-good = 1 67 | -------------------------------------------------------------------------------- /power/powerstatus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ## Read some values from the PMIC and print out what we find 3 | ### example i2cget -y -f 0 0x24 0x3 4 | 5 | import subprocess 6 | 7 | I2C_DEVICE = 0 8 | 9 | CHIP_ADDRESS = 0x24 10 | 11 | # register addresses we are interested in 12 | PPATH = 0x1 13 | CHGCONFIG0 = 0x3 14 | 15 | 16 | STATUS = 0xA 17 | PGOOD = 0xC 18 | 19 | # some bitmasks 20 | 21 | STATUS_AC = 1<<3 22 | STATUS_USB = 1<<2 23 | 24 | CHGCONFIG0_ACTIVE = 1<<3 # we are charging the battery 25 | 26 | # these labels are interpreted from the TPS65217 datasheet 27 | CHG0_LABELS = ["Temp sense error","Pre-charge Timedout","Charge Timedout","Active (charging)","Charge Termination Current","Thermal Suspend", "DPPM Reduction","Thermal Regulation"] 28 | STATUS_LABELS=["Push Button",None,"USB Power", "AC Power"]# skip the rest 29 | PGOOD_LABELS=["LDO2 power-good","LDO1 power-good","DCDC3 power-good","DCDC2 power-good","DCDC1 power-good", "LDO4 power-good","LDO3 power-good"] 30 | 31 | 32 | # get the I2C register, strip off \n and cast to int from hex 33 | # -y means non-interactive mode (just do it!) 34 | # -f forces the connection 35 | def query(reg=0): 36 | return int(subprocess.check_output(["i2cget","-y" ,"-f", str(I2C_DEVICE), str(CHIP_ADDRESS), str(reg)]).strip(),16) 37 | 38 | # display value of each bit in the register, along with its label 39 | def describe_bits(val,labels): 40 | for x in range(0,len(labels)): 41 | if(not labels[x]): # skip None labels 42 | continue 43 | msk = 1<3): 14 | return 15 | os.system("echo none > /sys/class/leds/beaglebone:green:usr%d/trigger"%n) 16 | os.system("echo 255 > /sys/class/leds/beaglebone:green:usr%d/brightness"%n) 17 | 18 | def ledOff(n=1): 19 | if(n<0 or n>3): 20 | return 21 | os.system("echo none > /sys/class/leds/beaglebone:green:usr%d/trigger"%n) 22 | os.system("echo 0 > /sys/class/leds/beaglebone:green:usr%d/brightness"%n) 23 | 24 | def fixLEDs(): 25 | triggers=["heartbeat","mmc0","cpu0","mmc1"] 26 | n=0 27 | for t in triggers: 28 | os.system("echo %s > /sys/class/leds/beaglebone:green:usr%d/trigger"%(t,n)) 29 | n+=1 30 | 31 | def flashLEDs(n=6, period=0.5, leds=[2,3]): 32 | # flash it! 33 | for x in range(0,n): 34 | for led in leds: 35 | ledOn(led) 36 | time.sleep(period) 37 | for led in leds: 38 | ledOff(led) 39 | time.sleep(period) 40 | 41 | class SafeShutdownDaemon(Daemon): 42 | def stopping(self): 43 | fixLEDs(); 44 | 45 | def run(self): 46 | my_logger = logging.getLogger('Safe Shutdown Service') 47 | my_logger.setLevel(logging.INFO) 48 | handler = logging.handlers.SysLogHandler(address = '/dev/log') 49 | my_logger.addHandler(handler) 50 | 51 | my_logger.info("Starting Safe Shutdown and Charge Monitor") 52 | 53 | fixLEDs() 54 | 55 | 56 | BATT_SHUTDOWN_S=10 57 | lastNotifySecond=0 58 | notifyMod = int(BATT_SHUTDOWN_S / 5.0) # notify five times in log 59 | 60 | timeOnBattery = 0; 61 | lastOnBattery = 0 62 | onBattery = False 63 | charging=False 64 | tmpCharging=False 65 | tmpBattery = False 66 | 67 | while True: 68 | tmpBattery = powerstatus.onBattery() 69 | tmpCharging = powerstatus.charging() 70 | 71 | ledOn(2) if(tmpBattery) else ledOff(2) 72 | ledOn(3) if(tmpCharging) else ledOff(3) 73 | if(charging!=tmpCharging): 74 | msg = "Started Charging Battery" if tmpCharging else "Stopped Charging Battery" 75 | my_logger.info(msg) 76 | 77 | if(onBattery!= tmpBattery): 78 | lastOnBattery=time.time() # start counting 79 | msg = "Switched to Battery Power" if tmpBattery else "Switched to wired power" 80 | my_logger.info(msg) 81 | 82 | 83 | onBattery=tmpBattery 84 | charging=tmpCharging 85 | 86 | if(onBattery): 87 | timeOnBattery+=(time.time()-lastOnBattery) 88 | lastOnBattery=time.time() 89 | 90 | if(timeOnBattery > BATT_SHUTDOWN_S): 91 | my_logger.info("On Battery power for %d secs - shutdown NOW!"%timeOnBattery) 92 | flashLEDs(n=4, period=0.5, leds=[0,1,2,3]) 93 | fixLEDs() 94 | os.system("shutdown now") 95 | 96 | elif(int(timeOnBattery) > lastNotifySecond and int(timeOnBattery)%notifyMod ==0): 97 | lastNotifySecond=int(timeOnBattery) 98 | my_logger.info("On Battery Power -- auto-shutdown in %d seconds"%(BATT_SHUTDOWN_S-int(timeOnBattery))) 99 | time.sleep(0.5) 100 | else: 101 | timeOnBattery=0 102 | time.sleep(5) 103 | 104 | 105 | 106 | if __name__ == "__main__": 107 | daemon = SafeShutdownDaemon('/tmp/safe-shutdown-daemon.pid') 108 | if len(sys.argv) == 2: 109 | if 'start' == sys.argv[1]: 110 | print "Starting safe shutdown script" 111 | daemon.start() 112 | elif 'stop' == sys.argv[1]: 113 | print "Stopping safe shutdown" 114 | daemon.stop() 115 | elif 'restart' == sys.argv[1]: 116 | print "Restarting safe shutdown" 117 | daemon.restart() 118 | elif 'test' == sys.argv[1]: 119 | print "Running daemon directly for testing" 120 | daemon.run() 121 | else: 122 | print "Unknown command" 123 | sys.exit(2) 124 | sys.exit(0) 125 | else: 126 | # print "usage: %s start|stop|restart" % sys.argv[0] 127 | daemon.start(True) -------------------------------------------------------------------------------- /power/daemon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ 3 | 4 | import sys, os, time, atexit 5 | from signal import SIGTERM 6 | 7 | class Daemon: 8 | """ 9 | A generic daemon class. 10 | 11 | Usage: subclass the Daemon class and override the run() method 12 | """ 13 | def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): 14 | self.stdin = stdin 15 | self.stdout = stdout 16 | self.stderr = stderr 17 | self.pidfile = pidfile 18 | 19 | def daemonize(self): 20 | """ 21 | do the UNIX double-fork magic, see Stevens' "Advanced 22 | Programming in the UNIX Environment" for details (ISBN 0201563177) 23 | http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 24 | """ 25 | try: 26 | pid = os.fork() 27 | if pid > 0: 28 | # exit first parent 29 | sys.exit(0) 30 | except OSError, e: 31 | sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 32 | sys.exit(1) 33 | 34 | # decouple from parent environment 35 | os.chdir("/") 36 | os.setsid() 37 | os.umask(0) 38 | 39 | # do second fork 40 | try: 41 | pid = os.fork() 42 | if pid > 0: 43 | # exit from second parent 44 | sys.exit(0) 45 | except OSError, e: 46 | sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 47 | sys.exit(1) 48 | 49 | # redirect standard file descriptors 50 | sys.stdout.flush() 51 | sys.stderr.flush() 52 | si = file(self.stdin, 'r') 53 | so = file(self.stdout, 'a+') 54 | se = file(self.stderr, 'a+', 0) 55 | os.dup2(si.fileno(), sys.stdin.fileno()) 56 | os.dup2(so.fileno(), sys.stdout.fileno()) 57 | os.dup2(se.fileno(), sys.stderr.fileno()) 58 | 59 | # write pidfile 60 | atexit.register(self.delpid) 61 | pid = str(os.getpid()) 62 | file(self.pidfile,'w+').write("%s\n" % pid) 63 | 64 | def delpid(self): 65 | os.remove(self.pidfile) 66 | 67 | def start(self,force=False): 68 | """ 69 | Start the daemon 70 | """ 71 | # Check for a pidfile to see if the daemon already runs 72 | if not force: 73 | try: 74 | pf = file(self.pidfile,'r') 75 | pid = int(pf.read().strip()) 76 | pf.close() 77 | except IOError: 78 | pid = None 79 | 80 | if pid: 81 | message = "pidfile %s already exist. Daemon already running?\n" 82 | sys.stderr.write(message % self.pidfile) 83 | sys.exit(1) 84 | 85 | # Start the daemon 86 | self.daemonize() 87 | self.run() 88 | 89 | def stop(self): 90 | """ 91 | Stop the daemon 92 | """ 93 | # Get the pid from the pidfile 94 | try: 95 | pf = file(self.pidfile,'r') 96 | pid = int(pf.read().strip()) 97 | pf.close() 98 | except IOError: 99 | pid = None 100 | 101 | if not pid: 102 | message = "pidfile %s does not exist. Daemon not running?\n" 103 | sys.stderr.write(message % self.pidfile) 104 | return # not an error in a restart 105 | 106 | # Try killing the daemon process 107 | try: 108 | self.stopping() 109 | time.sleep(0.5) 110 | while 1: 111 | os.kill(pid, SIGTERM) 112 | time.sleep(0.1) 113 | except OSError, err: 114 | err = str(err) 115 | if err.find("No such process") > 0: 116 | if os.path.exists(self.pidfile): 117 | os.remove(self.pidfile) 118 | else: 119 | print str(err) 120 | sys.exit(1) 121 | 122 | def restart(self): 123 | """ 124 | Restart the daemon 125 | """ 126 | self.stop() 127 | self.start() 128 | 129 | def run(self): 130 | """ 131 | You should override this method when you subclass Daemon. It will be called after the process has been 132 | daemonized by start() or restart(). 133 | """ 134 | def stopping(self): 135 | """ called when we are stopping""" 136 | 137 | --------------------------------------------------------------------------------