doc for blinkenLights and rename linear to triangle

This commit is contained in:
petrucci4prez 2017-06-18 16:03:39 -04:00
parent 61201da8c6
commit 4f7a862f43
2 changed files with 44 additions and 22 deletions

View File

@ -10,10 +10,15 @@ from itertools import chain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Blinkenlights(ExceptionThread): class Blinkenlights(ExceptionThread):
'''
Controls one LED on a GPIO pin. LED brightness can be control via
pulse-width modulation (pwm) and can be set to a constant brightness or
fluctuate as a triangle wave or square wave, each with varying periods.
'''
def __init__(self, pin, cyclePeriod=2): def __init__(self, pin, cyclePeriod=2):
self._stopper = Event() self._stopper = Event()
self._blink = Event() self._blink = Event()
self._linear = Event() self._triangle = Event()
# number of pwm adjustments madeper duty cycle, note stepsize is in half # number of pwm adjustments madeper duty cycle, note stepsize is in half
# because we spend first half of period decreasing duty cycle and the # because we spend first half of period decreasing duty cycle and the
@ -28,9 +33,15 @@ class Blinkenlights(ExceptionThread):
GPIO.setup(pin, GPIO.OUT) GPIO.setup(pin, GPIO.OUT)
pwm = GPIO.PWM(self._pin, 60) pwm = GPIO.PWM(self._pin, 60)
def linearLoop(): def triangleLoop():
'''
Controls the brightness in triangle-wave mode. Note that this will
exit as soon as _triangle or _blink events are cleared...this may
seem convoluted but is necessary to ensure clean response times
when the mode is changed
'''
for dc in chain(range(100, -1, -self._stepsize), range(0, 101, self._stepsize)): for dc in chain(range(100, -1, -self._stepsize), range(0, 101, self._stepsize)):
t = (self._linear.is_set(), self._blink.is_set()) t = (self._triangle.is_set(), self._blink.is_set())
if t == (True, True): if t == (True, True):
pwm.ChangeDutyCycle(dc) pwm.ChangeDutyCycle(dc)
time.sleep(self._sleeptime) time.sleep(self._sleeptime)
@ -39,28 +50,39 @@ class Blinkenlights(ExceptionThread):
return (True, True) return (True, True)
def blinkLights(): def blinkLights():
'''
Uses mode to control brightness. This function has three phases in
its lifetime:
1) start PWM on the GPIO pin
2) brightness control loop, which exits on setting _stopper event
3) stop PWM (if this doesn't happen we segfault)
Within the brightness control loop, flow is controled by events,
which ensure good response times when we transition b/t states as
well as high cpu efficiency (no busy waits).
'''
pwm.start(0) pwm.start(0)
while not self._stopper.isSet(): while not self._stopper.isSet():
if self._blink.is_set(): if self._blink.is_set():
linearSet, blinkSet = linearLoop() triangleSet, blinkSet = triangleLoop()
if not blinkSet: if not blinkSet:
continue continue
elif not linearSet: elif not triangleSet:
t = self._sleeptime*self._steps/2 t = self._sleeptime*self._steps/2
pwm.ChangeDutyCycle(100) pwm.ChangeDutyCycle(100)
self._linear.wait(timeout=t) self._triangle.wait(timeout=t)
if self._linear.is_set() or not self._blink.is_set(): if self._triangle.is_set() or not self._blink.is_set():
continue continue
pwm.ChangeDutyCycle(0) pwm.ChangeDutyCycle(0)
self._linear.wait(timeout=t) self._triangle.wait(timeout=t)
else: else:
pwm.ChangeDutyCycle(100) pwm.ChangeDutyCycle(100)
self._blink.wait() self._blink.wait()
pwm.stop() # required to avoid core dumps when process terminates pwm.stop()
super().__init__(target=blinkLights, daemon=True) super().__init__(target=blinkLights, daemon=True)
@ -72,25 +94,25 @@ class Blinkenlights(ExceptionThread):
if self.is_alive(): if self.is_alive():
self._stopper.set() self._stopper.set()
self._blink.set() self._blink.set()
self._linear.set() self._triangle.set()
logger.debug('Stopping LED on pin %s', self._pin) logger.debug('Stopping LED on pin %s', self._pin)
def setCyclePeriod(self, cyclePeriod): def setCyclePeriod(self, cyclePeriod):
self._sleeptime = cyclePeriod/self._steps self._sleeptime = cyclePeriod/self._steps
def setLinear(self, toggle): def setTriangle(self, toggle):
if toggle: if toggle:
self._linear.set() self._triangle.set()
else: else:
self._linear.clear() self._triangle.clear()
def setBlink(self, toggle): def setBlink(self, toggle):
if toggle: if toggle:
self._blink.set() self._blink.set()
# unblock the _linear Event if threads are waiting on it # unblock the _triangle Event if threads are waiting on it
if not self._linear.is_set(): if not self._triangle.is_set():
self._linear.set() self._triangle.set()
self._linear.clear() self._triangle.clear()
else: else:
self._blink.clear() self._blink.clear()

View File

@ -201,12 +201,12 @@ class StateMachine:
def squareBlink(t): def squareBlink(t):
LED.setBlink(True) LED.setBlink(True)
LED.setLinear(False) LED.setTriangle(False)
LED.setCyclePeriod(t) LED.setCyclePeriod(t)
def linearBlink(t): def triangleBlink(t):
LED.setBlink(True) LED.setBlink(True)
LED.setLinear(True) LED.setTriangle(True)
LED.setCyclePeriod(t) LED.setCyclePeriod(t)
stateObjs = [ stateObjs = [
@ -223,7 +223,7 @@ class StateMachine:
), ),
_State( _State(
name = 'armed', name = 'armed',
entryCallbacks = [partial(linearBlink, 1)], entryCallbacks = [partial(triangleBlink, 1)],
sound = sfx['armed'] sound = sfx['armed']
), ),
_State( _State(
@ -245,7 +245,7 @@ class StateMachine:
), ),
_State( _State(
name = 'tripped', name = 'tripped',
entryCallbacks = [partial(linearBlink, 0.5), intruderAlert], entryCallbacks = [partial(triangleBlink, 0.5), intruderAlert],
sound = sfx['tripped'] sound = sfx['tripped']
) )
] ]