Refactor into Python daemon and simplified shell
This commit makes a major change to the organization and operation of the RPi BMC software. The 'shell' (`bmc.sh`) has been greatly simplified, removing all instances of `wiringpi` GPIO code. The shell communicates with a new Python daemon via a pair of named pipes in `/run/bmcd`. The Python daemon starts and immediately executes two threads: 1) The first manages reading from `/run/bmcd/bmcd.cmd`, which handles the passing of commands from `bmc.sh`, such as 'powersw_press' or 'locate_on'. 2) The second manages writing the current host state out to `/run/bmcd/bmcd.state`, to be read from `bmc.sh` when needed. It does this every second to avoid blocking. An additional thread with an Event handler manages the flashing power LED for the `locate` functions.
This commit is contained in:
parent
a52f8b071f
commit
e56002baf8
|
@ -4,25 +4,18 @@ stty eof undef
|
||||||
stty intr undef
|
stty intr undef
|
||||||
|
|
||||||
hostsystem="$( cat /etc/bmchost )"
|
hostsystem="$( cat /etc/bmchost )"
|
||||||
packages=( screen wiringpi )
|
bmcd_cmdpipe="/run/bmcd/bmcd.cmd"
|
||||||
pkgfail=""
|
bmcd_statepipe="/run/bmcd/bmcd.state"
|
||||||
for package in ${packages[@]}; do
|
|
||||||
dpkg -l | grep "^ii ${package}" &>/dev/null || pkgfail="true"
|
|
||||||
done
|
|
||||||
if test -n "$pkgfail"; then
|
|
||||||
echo -n "Installing required packages... "
|
|
||||||
sudo apt update &>/dev/null
|
|
||||||
sudo apt install -y ${packages[@]} &>/dev/null
|
|
||||||
echo "done."
|
|
||||||
fi
|
|
||||||
|
|
||||||
help() {
|
help() {
|
||||||
echo -e "Available commands:"
|
echo -e "Available commands:"
|
||||||
echo -e " \e[1mstate\e[0m - Show the system power state"
|
echo -e " \e[1mstate\e[0m - Show the system power state"
|
||||||
echo -e " \e[1mconsole\e[0m - Connect to host via serial console; ^A+D to disconnect"
|
echo -e " \e[1mconsole\e[0m - Connect to host via serial console; ^A+D to disconnect"
|
||||||
echo -e " \e[1mpowersw\e[0m - Press power switch on host"
|
echo -e " \e[1mpower\e[0m - Press power switch on host"
|
||||||
echo -e " \e[1mresetsw\e[0m - Press reset switch on host"
|
echo -e " \e[1mreset\e[0m - Press reset switch on host"
|
||||||
echo -e " \e[1mkill\e[0m - Forcibly power off host"
|
echo -e " \e[1mkill\e[0m - Forcibly power off host"
|
||||||
|
echo -e " \e[1mlocate\e[0m - Enable locator (flash power LED)"
|
||||||
|
echo -e " \e[1munlocate\e[0m - Disable locator"
|
||||||
echo -e " \e[1mhelp\e[0m - This help menu"
|
echo -e " \e[1mhelp\e[0m - This help menu"
|
||||||
echo -e " \e[1mbmc\e[0m - Show BMC information"
|
echo -e " \e[1mbmc\e[0m - Show BMC information"
|
||||||
echo -e " \e[1mhostname\e[0m - Set BMC hostname"
|
echo -e " \e[1mhostname\e[0m - Set BMC hostname"
|
||||||
|
@ -60,33 +53,30 @@ setpassword() {
|
||||||
echo "Passwords to not match!"
|
echo "Passwords to not match!"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
resetsw() {
|
resetsw_press() {
|
||||||
echo -n "Pressing reset switch... "
|
echo "Pressing reset switch."
|
||||||
gpio mode 0 out
|
echo "resetsw_press" > ${bmcd_cmdpipe}
|
||||||
gpio write 0 1
|
|
||||||
sleep 1
|
|
||||||
gpio write 0 0
|
|
||||||
sleep 1
|
|
||||||
echo "done."
|
|
||||||
}
|
}
|
||||||
powersw() {
|
powersw_press() {
|
||||||
if [ "$1" == "hard" ]; then
|
echo "Holding power switch."
|
||||||
delay='sleep 10'
|
echo "powersw_hold" > ${bmcd_cmdpipe}
|
||||||
echo -n "Holding power switch... "
|
|
||||||
else
|
|
||||||
delay='sleep 1'
|
|
||||||
echo -n "Pressing power switch... "
|
|
||||||
fi
|
|
||||||
gpio mode 1 out
|
|
||||||
gpio write 1 1
|
|
||||||
$delay
|
|
||||||
gpio write 1 0
|
|
||||||
sleep 2
|
sleep 2
|
||||||
echo "done."
|
}
|
||||||
|
powersw_hold() {
|
||||||
|
echo "Pressing power switch."
|
||||||
|
echo "powersw_press" > ${bmcd_cmdpipe}
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
locate_on() {
|
||||||
|
echo "Enabling locator - host power LED will flash."
|
||||||
|
echo "locate_on" > ${bmcd_cmdpipe}
|
||||||
|
}
|
||||||
|
locate_off() {
|
||||||
|
echo "Disabling locator."
|
||||||
|
echo "locate_off" > ${bmcd_cmdpipe}
|
||||||
}
|
}
|
||||||
readpower() {
|
readpower() {
|
||||||
gpio mode 2 in
|
powerstate_raw=$(cat ${bmcd_statepipe})
|
||||||
powerstate_raw=$(gpio read 2)
|
|
||||||
if [ "${powerstate_raw}" -eq 1 ]; then
|
if [ "${powerstate_raw}" -eq 1 ]; then
|
||||||
powerstate="\e[32mOn\e[0m"
|
powerstate="\e[32mOn\e[0m"
|
||||||
else
|
else
|
||||||
|
@ -118,26 +108,37 @@ case $input in
|
||||||
;;
|
;;
|
||||||
'console')
|
'console')
|
||||||
echo "Starting console..."
|
echo "Starting console..."
|
||||||
|
# Connect to screen, or start it
|
||||||
sudo screen -r serialconsole &>/dev/null || sudo screen -S serialconsole /dev/ttyUSB0 115200
|
sudo screen -r serialconsole &>/dev/null || sudo screen -S serialconsole /dev/ttyUSB0 115200
|
||||||
|
# If the user killed screen, restart it - just in case
|
||||||
|
pgrep screen &>/dev/null || sudo screen -S serialconsole /dev/ttyUSB0 115200
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
'powersw')
|
'powersw')
|
||||||
powersw soft
|
powersw_press
|
||||||
readpower
|
readpower
|
||||||
echo -e "Host state: $powerstate"
|
echo -e "Host state: $powerstate"
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
'resetsw')
|
'resetsw')
|
||||||
resetsw
|
resetsw_press
|
||||||
readpower
|
readpower
|
||||||
echo -e "Host state: $powerstate"
|
echo -e "Host state: $powerstate"
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
'kill')
|
'kill')
|
||||||
powersw hard
|
powersw_hold
|
||||||
readpower
|
readpower
|
||||||
echo -e "Host state: $powerstate"
|
echo -e "Host state: $powerstate"
|
||||||
echo
|
echo
|
||||||
|
;;
|
||||||
|
'locate')
|
||||||
|
locate_on
|
||||||
|
echo
|
||||||
|
;;
|
||||||
|
'unlocate')
|
||||||
|
locate_off
|
||||||
|
echo
|
||||||
;;
|
;;
|
||||||
'help')
|
'help')
|
||||||
help
|
help
|
||||||
|
|
117
bmcd
117
bmcd
|
@ -1,9 +1,9 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import socket, os, time, struct
|
import socket, os, time, struct
|
||||||
from threading import Thread
|
from threading import Thread, Event
|
||||||
from daemon import runner
|
from daemon import runner
|
||||||
#import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
gpio_state = '11'
|
gpio_state = '11'
|
||||||
gpio_psw = '12'
|
gpio_psw = '12'
|
||||||
|
@ -14,21 +14,73 @@ bmcd_state = '/run/bmcd/bmcd.state'
|
||||||
bmcd_cmd = '/run/bmcd/bmcd.cmd'
|
bmcd_cmd = '/run/bmcd/bmcd.cmd'
|
||||||
pidfile = '/run/bmcd/bmcd.pid'
|
pidfile = '/run/bmcd/bmcd.pid'
|
||||||
|
|
||||||
class readcmd(Thread):
|
is_pled_flashing = Event()
|
||||||
def run(self):
|
|
||||||
while True:
|
|
||||||
print "Hi"
|
|
||||||
line = fcmd.readline()
|
|
||||||
print line
|
|
||||||
line = ""
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
class writestate(Thread):
|
def powerled_on():
|
||||||
def run(self):
|
GPIO.input(gpip_pled, 1)
|
||||||
while True:
|
|
||||||
print "Derp"
|
def powerled_off():
|
||||||
fstate.write("Writing state\n") # Write str length and str
|
GPIO.input(gpip_pled, 0)
|
||||||
time.sleep(1)
|
|
||||||
|
def powerled_flash(is_pled_flashing):
|
||||||
|
while is_pled_flashing.isSet():
|
||||||
|
GPIO.input(gpip_pled, 1)
|
||||||
|
time.sleep(1)
|
||||||
|
GPIO.input(gpip_pled, 0)
|
||||||
|
time.sleep(1)
|
||||||
|
is_pled_flashing.clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
def powersw_press():
|
||||||
|
GPIO.input(gpip_psw, 1)
|
||||||
|
time.sleep(0.5)
|
||||||
|
GPIO.input(gpio_psw, 0)
|
||||||
|
|
||||||
|
def powersw_hold():
|
||||||
|
GPIO.input(gpip_psw, 1)
|
||||||
|
time.sleep(8)
|
||||||
|
GPIO.input(gpio_psw, 0)
|
||||||
|
|
||||||
|
def resetsw_press():
|
||||||
|
GPIO.input(gpip_rsw, 1)
|
||||||
|
time.sleep(0.5)
|
||||||
|
GPIO.input(gpio_rsw, 0)
|
||||||
|
|
||||||
|
def locate_on():
|
||||||
|
is_pled_flashing.set()
|
||||||
|
t = Thread(name='non-block', target=powerled_flash, args=(is_pled_flashing,))
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def locate_off():
|
||||||
|
is_pled_flashing.clear()
|
||||||
|
|
||||||
|
def readcmd():
|
||||||
|
fcmd = open(bmcd_cmd, 'r+b', 0)
|
||||||
|
while True:
|
||||||
|
line = fcmd.readline()
|
||||||
|
try:
|
||||||
|
globals()[line.rstrip()]()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def writestate(is_pled_flashing):
|
||||||
|
fstate = open(bmcd_state, 'w+b', 0)
|
||||||
|
state_prev = 1
|
||||||
|
while True:
|
||||||
|
state_now = GPIO.input(gpio_state)
|
||||||
|
if state_now != state_prev:
|
||||||
|
fstate.write(str(state_now))
|
||||||
|
state_prev = state_now
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not is_pled_flashing.isSet():
|
||||||
|
if state_now == 1:
|
||||||
|
powerled_on()
|
||||||
|
else:
|
||||||
|
powerled_off()
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
class App():
|
class App():
|
||||||
|
@ -39,30 +91,25 @@ class App():
|
||||||
self.pidfile_path = pidfile
|
self.pidfile_path = pidfile
|
||||||
self.pidfile_timeout = 5
|
self.pidfile_timeout = 5
|
||||||
def run(self):
|
def run(self):
|
||||||
print "Starting daemon."
|
|
||||||
if not os.path.exists(bmcd_state):
|
if not os.path.exists(bmcd_state):
|
||||||
os.mkfifo(bmcd_state)
|
os.mkfifo(bmcd_state)
|
||||||
if not os.path.exists(bmcd_cmd):
|
if not os.path.exists(bmcd_cmd):
|
||||||
os.mkfifo(bmcd_cmd)
|
os.mkfifo(bmcd_cmd)
|
||||||
|
|
||||||
fstate = open(bmcd_state, 'w+b', 0)
|
GPIO.setmode(GPIO.BOARD)
|
||||||
fcmd = open(bmcd_cmd, 'r+b', 0)
|
GPIO.setup(gpio_state, GPIO.OUT)
|
||||||
|
GPIO.setup(gpio_psw, GPIO.OUT)
|
||||||
# thread.start_new_thread(readcmd(fcmd))
|
GPIO.setup(gpio_rsw, GPIO.IN)
|
||||||
# thread.start_new_thread(writestate(fstate))
|
GPIO.setup(gpio_pled, GPIO.OUT)
|
||||||
wthread = Thread(target=writestate(fstate))
|
|
||||||
rthread = Thread(target=readcmd(fcmd))
|
|
||||||
wthread.daemon = True
|
|
||||||
rthread.daemon = True
|
|
||||||
wthread.start()
|
|
||||||
rthread.start()
|
|
||||||
|
|
||||||
# GPIO.setmode(GPIO.BOARD)
|
|
||||||
# GPIO.setup(gpio_state, GPIO.OUT)
|
|
||||||
# GPIO.setup(gpio_psw, GPIO.OUT)
|
|
||||||
# GPIO.setup(gpio_rsw, GPIO.IN)
|
|
||||||
# GPIO.setup(gpio_pled, GPIO.OUT)
|
|
||||||
|
|
||||||
|
t1 = Thread(target=readcmd)
|
||||||
|
t2 = Thread(target=writestate, args=(is_pled_flashing,))
|
||||||
|
t1.setDaemon(True)
|
||||||
|
t2.setDaemon(True)
|
||||||
|
t1.start()
|
||||||
|
t2.start()
|
||||||
|
while True:
|
||||||
|
pass
|
||||||
|
|
||||||
app = App()
|
app = App()
|
||||||
daemon_runner = runner.DaemonRunner(app)
|
daemon_runner = runner.DaemonRunner(app)
|
||||||
|
|
Loading…
Reference in New Issue