GPIO matches StateMachine now
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Photobooth - a flexible photo booth software
|
||||
# Copyright (C) 2018 Balthasar Reuter <photobooth at re - web dot eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gpiozero import LED, Button
|
||||
|
||||
|
||||
class Gpio:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._buttons = []
|
||||
self._lamps = []
|
||||
|
||||
def setButton(self, bcm_pin, handler):
|
||||
|
||||
self._buttons.append(Button(bcm_pin))
|
||||
self._buttons[-1].when_pressed = handler
|
||||
|
||||
def setLamp(self, bcm_pin):
|
||||
|
||||
self._lamps.append(LED(bcm_pin))
|
||||
return len(self._lamps) - 1
|
||||
|
||||
def lampOn(self, index):
|
||||
|
||||
self._lamps[index].on()
|
||||
|
||||
def lampOff(self, index):
|
||||
|
||||
self._lamps[index].off()
|
||||
|
||||
def lampToggle(self, index):
|
||||
|
||||
self._lamps[index].toggle()
|
||||
174
photobooth/gpio/__init__.py
Normal file
174
photobooth/gpio/__init__.py
Normal file
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Photobooth - a flexible photo booth software
|
||||
# Copyright (C) 2018 Balthasar Reuter <photobooth at re - web dot eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
|
||||
from .. import StateMachine
|
||||
from ..Threading import Workers
|
||||
|
||||
|
||||
class Gpio:
|
||||
|
||||
def __init__(self, config, comm):
|
||||
|
||||
super().__init__()
|
||||
|
||||
self._comm = comm
|
||||
self._gpio = None
|
||||
|
||||
self._is_trigger = False
|
||||
self._is_enabled = config.getBool('Gpio', 'enable')
|
||||
|
||||
self.initGpio(config)
|
||||
|
||||
def initGpio(self, config):
|
||||
|
||||
if self._is_enabled:
|
||||
self._gpio = Entities()
|
||||
|
||||
lamp_pin = config.getInt('Gpio', 'lamp_pin')
|
||||
trigger_pin = config.getInt('Gpio', 'trigger_pin')
|
||||
exit_pin = config.getInt('Gpio', 'exit_pin')
|
||||
|
||||
logging.info(('GPIO enabled (lamp_pin=%d, trigger_pin=%d, '
|
||||
'exit_pin=%d)'), lamp_pin, trigger_pin, exit_pin)
|
||||
|
||||
self._gpio.setButton(trigger_pin, self.trigger)
|
||||
self._gpio.setButton(exit_pin, self.exit)
|
||||
self._lamp = self._gpio.setLamp(lamp_pin)
|
||||
else:
|
||||
logging.info('GPIO disabled')
|
||||
|
||||
def run(self):
|
||||
|
||||
for state in self._comm.iter(Workers.GPIO):
|
||||
self.handleState(state)
|
||||
|
||||
return True
|
||||
|
||||
def handleState(self, state):
|
||||
|
||||
if isinstance(state, StateMachine.IdleState):
|
||||
self.showIdle()
|
||||
elif isinstance(state, StateMachine.GreeterState):
|
||||
self.showGreeter()
|
||||
elif isinstance(state, StateMachine.CountdownState):
|
||||
self.showCountdown()
|
||||
elif isinstance(state, StateMachine.CaptureState):
|
||||
self.showCapture()
|
||||
elif isinstance(state, StateMachine.AssembleState):
|
||||
self.showAssemble()
|
||||
elif isinstance(state, StateMachine.ReviewState):
|
||||
self.showReview()
|
||||
elif isinstance(state, StateMachine.PostprocessState):
|
||||
self.showPostprocess()
|
||||
elif isinstance(state, StateMachine.TeardownState):
|
||||
self.teardown(state)
|
||||
|
||||
def teardown(self, state):
|
||||
|
||||
pass
|
||||
|
||||
def enableTrigger(self):
|
||||
|
||||
if self._is_enabled:
|
||||
self._is_trigger = True
|
||||
self._gpio.lampOn(self._lamp)
|
||||
|
||||
def disableTrigger(self):
|
||||
|
||||
if self._is_enabled:
|
||||
self._is_trigger = False
|
||||
self._gpio.lampOff(self._lamp)
|
||||
|
||||
def trigger(self):
|
||||
|
||||
if self._is_trigger:
|
||||
self.disableTrigger()
|
||||
self._comm.send(Workers.MASTER, StateMachine.GpioEvent('trigger'))
|
||||
|
||||
def exit(self):
|
||||
|
||||
self._comm.send(
|
||||
Workers.Master,
|
||||
StateMachine.TeardownEvent(StateMachine.TeardownEvent.WELCOME))
|
||||
|
||||
def showIdle(self):
|
||||
|
||||
self.enableTrigger()
|
||||
|
||||
def showGreeter(self):
|
||||
|
||||
self.disableTrigger()
|
||||
|
||||
def showCountdown(self):
|
||||
|
||||
pass
|
||||
|
||||
def showCapture(self):
|
||||
|
||||
pass
|
||||
|
||||
def showAssemble(self):
|
||||
|
||||
pass
|
||||
|
||||
def showReview(self):
|
||||
|
||||
pass
|
||||
|
||||
def showPostprocess(self):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class Entities:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super().__init__()
|
||||
|
||||
import gpiozero
|
||||
self.LED = gpiozero.LED
|
||||
self.Button = gpiozero.Button
|
||||
|
||||
self._buttons = []
|
||||
self._lamps = []
|
||||
|
||||
def setButton(self, bcm_pin, handler):
|
||||
|
||||
self._buttons.append(self.Button(bcm_pin))
|
||||
self._buttons[-1].when_pressed = handler
|
||||
|
||||
def setLamp(self, bcm_pin):
|
||||
|
||||
self._lamps.append(self.LED(bcm_pin))
|
||||
return len(self._lamps) - 1
|
||||
|
||||
def lampOn(self, index):
|
||||
|
||||
self._lamps[index].on()
|
||||
|
||||
def lampOff(self, index):
|
||||
|
||||
self._lamps[index].off()
|
||||
|
||||
def lampToggle(self, index):
|
||||
|
||||
self._lamps[index].toggle()
|
||||
@@ -30,6 +30,7 @@ import sys
|
||||
|
||||
from . import camera, gui
|
||||
from .Config import Config
|
||||
from .gpio import Gpio
|
||||
from .util import lookup_and_import
|
||||
from .StateMachine import Context, ErrorEvent
|
||||
from .Threading import Communicator, Workers
|
||||
@@ -38,7 +39,7 @@ from .worker import Worker
|
||||
|
||||
class CameraProcess(mp.Process):
|
||||
|
||||
def __init__(self, config, comm):
|
||||
def __init__(self, argv, config, comm):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
@@ -60,41 +61,61 @@ class CameraProcess(mp.Process):
|
||||
self._comm.send(Workers.MASTER, ErrorEvent('Camera', str(e)))
|
||||
|
||||
|
||||
class WorkerProcess(mp.Process):
|
||||
|
||||
def __init__(self, config, comm):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self.cfg = config
|
||||
self.comm = comm
|
||||
|
||||
def run(self):
|
||||
|
||||
while True:
|
||||
try:
|
||||
if Worker(self.cfg, self.comm).run():
|
||||
break
|
||||
except Exception as e:
|
||||
self._comm.send(Workers.MASTER, ErrorEvent('Worker', str(e)))
|
||||
|
||||
|
||||
class GuiProcess(mp.Process):
|
||||
|
||||
def __init__(self, argv, config, communicator):
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.argv = argv
|
||||
self.cfg = config
|
||||
self.comm = communicator
|
||||
self._argv = argv
|
||||
self._cfg = config
|
||||
self._comm = communicator
|
||||
|
||||
def run(self):
|
||||
|
||||
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'),
|
||||
Gui = lookup_and_import(gui.modules, self._cfg.get('Gui', 'module'),
|
||||
'gui')
|
||||
sys.exit(Gui(self.argv, self.cfg, self.comm).run())
|
||||
return Gui(self._argv, self._cfg, self._comm).run()
|
||||
|
||||
|
||||
class WorkerProcess(mp.Process):
|
||||
|
||||
def __init__(self, argv, config, comm):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self._cfg = config
|
||||
self._comm = comm
|
||||
|
||||
def run(self):
|
||||
|
||||
while True:
|
||||
try:
|
||||
if Worker(self._cfg, self._comm).run():
|
||||
break
|
||||
except Exception as e:
|
||||
self._comm.send(Workers.MASTER, ErrorEvent('Worker', str(e)))
|
||||
|
||||
|
||||
class GpioProcess(mp.Process):
|
||||
|
||||
def __init__(self, argv, config, comm):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self._cfg = config
|
||||
self._comm = comm
|
||||
|
||||
def run(self):
|
||||
|
||||
while True:
|
||||
try:
|
||||
if Gpio(self._cfg, self._comm).run():
|
||||
break
|
||||
except Exception as e:
|
||||
self.comm.send(Workers.MASTER, ErrorEvent('Gpio', str(e)))
|
||||
|
||||
|
||||
def run(argv):
|
||||
@@ -107,29 +128,28 @@ def run(argv):
|
||||
comm = Communicator()
|
||||
context = Context(comm)
|
||||
|
||||
# Initialize processes: We use four processes here:
|
||||
# 1. Camera processing
|
||||
# 2. Postprocessing
|
||||
# Initialize processes: We use five processes here:
|
||||
# 1. Master that collects events and distributes state changes
|
||||
# 2. Camera handling
|
||||
# 3. GUI
|
||||
# 4. Master
|
||||
camera_proc = CameraProcess(config, comm) # camera_conn, worker_queue)
|
||||
camera_proc.start()
|
||||
# 4. Postprocessing worker
|
||||
# 5. GPIO handler
|
||||
proc_classes = (CameraProcess, WorkerProcess, GuiProcess, GpioProcess)
|
||||
procs = [P(argv, config, comm) for P in proc_classes]
|
||||
|
||||
worker_proc = WorkerProcess(config, comm)
|
||||
worker_proc.start()
|
||||
|
||||
gui_proc = GuiProcess(argv, config, comm)
|
||||
gui_proc.start()
|
||||
for proc in procs:
|
||||
proc.start()
|
||||
|
||||
# Enter main loop
|
||||
for event in comm.iter(Workers.MASTER):
|
||||
exit_code = context.handleEvent(event)
|
||||
if exit_code in (0, 123):
|
||||
break
|
||||
|
||||
# Wait for processes to finish
|
||||
gui_proc.join()
|
||||
worker_proc.join()
|
||||
camera_proc.join()
|
||||
for proc in procs:
|
||||
proc.join()
|
||||
|
||||
logging.debug('All processes joined, returning code {}'. format(exit_code))
|
||||
|
||||
return exit_code
|
||||
|
||||
Reference in New Issue
Block a user