implemented reset command.
fixing bugs in statemachine and storyboard.
This commit is contained in:
parent
927204b00a
commit
7ce7b70499
4 changed files with 76 additions and 42 deletions
|
@ -58,6 +58,7 @@ class SerialCommands(Enum):
|
||||||
RECORD = b'C'
|
RECORD = b'C'
|
||||||
|
|
||||||
REWIND = b'R'
|
REWIND = b'R'
|
||||||
|
RESET = b'X'
|
||||||
|
|
||||||
DEBUG_SCROLL = b'S'
|
DEBUG_SCROLL = b'S'
|
||||||
DEBUG_SENSORS = b'Z'
|
DEBUG_SENSORS = b'Z'
|
||||||
|
@ -106,6 +107,24 @@ class PizzaHAL:
|
||||||
"""
|
"""
|
||||||
return self.lid_switch.is_pressed
|
return self.lid_switch.is_pressed
|
||||||
|
|
||||||
|
@property
|
||||||
|
def helo1(self) -> bool:
|
||||||
|
"""
|
||||||
|
Returns the status of the HELO1 pin
|
||||||
|
"""
|
||||||
|
return bool(self.helo1.value)
|
||||||
|
|
||||||
|
@helo1.setter
|
||||||
|
def helo1(self, value: bool):
|
||||||
|
self.helo1.value = 1 if value else 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def helo2(self) -> bool:
|
||||||
|
"""
|
||||||
|
Returns the value of the HELO2 pin (read only)
|
||||||
|
"""
|
||||||
|
return bool(self.helo2.value)
|
||||||
|
|
||||||
def init_connection(self):
|
def init_connection(self):
|
||||||
"""
|
"""
|
||||||
Set HELO1 pin to `High`, wait for HELO2 to be set `High` by microcontroller.
|
Set HELO1 pin to `High`, wait for HELO2 to be set `High` by microcontroller.
|
||||||
|
@ -213,6 +232,9 @@ class PizzaHAL:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def flush_serial(self):
|
def flush_serial(self):
|
||||||
|
"""
|
||||||
|
Clear the serial connection from unhandled responses.
|
||||||
|
"""
|
||||||
self.serialcon.read_all()
|
self.serialcon.read_all()
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,6 +262,13 @@ def rewind(hal: PizzaHAL, **kwargs):
|
||||||
hal.send_cmd(SerialCommands.REWIND, ignore_lid=True)
|
hal.send_cmd(SerialCommands.REWIND, ignore_lid=True)
|
||||||
|
|
||||||
|
|
||||||
|
def reset(hal: PizzaHAL, **kwargs):
|
||||||
|
"""
|
||||||
|
Prepare microcontroller for reset.
|
||||||
|
"""
|
||||||
|
hal.send_cmd(SerialCommands.RESET, ignore_lid=True)
|
||||||
|
|
||||||
|
|
||||||
def turn_off(hal: PizzaHAL, **kwargs):
|
def turn_off(hal: PizzaHAL, **kwargs):
|
||||||
"""
|
"""
|
||||||
Turn off the lights.
|
Turn off the lights.
|
||||||
|
@ -303,15 +332,15 @@ def wait_for_input(hal: PizzaHAL,
|
||||||
|
|
||||||
resp = resp[1]
|
resp = resp[1]
|
||||||
if resp == 1:
|
if resp == 1:
|
||||||
blue_cb(**kwargs)
|
blue_cb()
|
||||||
elif resp == 2:
|
elif resp == 2:
|
||||||
red_cb(**kwargs)
|
red_cb()
|
||||||
elif resp == 4:
|
elif resp == 4:
|
||||||
yellow_cb(**kwargs)
|
yellow_cb()
|
||||||
elif resp == 8:
|
elif resp == 8:
|
||||||
green_cb(**kwargs)
|
green_cb()
|
||||||
elif timeout_cb is not None:
|
elif timeout_cb is not None:
|
||||||
timeout_cb(**kwargs)
|
timeout_cb()
|
||||||
|
|
||||||
|
|
||||||
def set_light(hal: PizzaHAL,
|
def set_light(hal: PizzaHAL,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from email.policy import default
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
@ -11,18 +12,17 @@ logger = logging.getLogger('pizzactrl.main')
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option('--move', is_flag=True)
|
|
||||||
@click.option('--test', is_flag=True, default=False)
|
@click.option('--test', is_flag=True, default=False)
|
||||||
@click.option('--debug', is_flag=True, default=False)
|
@click.option('--debug', is_flag=True, default=False)
|
||||||
@click.option('--loop', is_flag=True, default=False)
|
@click.option('--loop', is_flag=True, default=False)
|
||||||
def main(move: bool=False, test: bool=False, debug: bool=False, loop: bool=False):
|
def main(test: bool=False, debug: bool=False, loop: bool=False):
|
||||||
if debug or test:
|
if debug or test:
|
||||||
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
|
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
|
||||||
else:
|
else:
|
||||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
||||||
|
|
||||||
hal = PizzaHAL()
|
hal = PizzaHAL()
|
||||||
sm = Statemachine(hal, STORYBOARD, move=move, loop=loop, test=test)
|
sm = Statemachine(hal, STORYBOARD, loop=loop, test=test)
|
||||||
|
|
||||||
sm.test = test
|
sm.test = test
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from enum import Enum, auto
|
||||||
|
|
||||||
from pizzactrl import fs_names
|
from pizzactrl import fs_names
|
||||||
from .storyboard import Language, Storyboard
|
from .storyboard import Language, Storyboard
|
||||||
from .hal_serial import SerialCommunicationError, CommunicationError, PizzaHAL, wait_for_input, play_sound, turn_off
|
from .hal_serial import SerialCommunicationError, CommunicationError, PizzaHAL, wait_for_input, play_sound, turn_off, reset
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ class Statemachine:
|
||||||
hal: PizzaHAL,
|
hal: PizzaHAL,
|
||||||
story: Storyboard,
|
story: Storyboard,
|
||||||
default_lang=Language.NOT_SET,
|
default_lang=Language.NOT_SET,
|
||||||
move: bool = False,
|
|
||||||
loop: bool = True,
|
loop: bool = True,
|
||||||
test: bool = False):
|
test: bool = False):
|
||||||
self.hal = hal
|
self.hal = hal
|
||||||
|
@ -41,7 +40,7 @@ class Statemachine:
|
||||||
self.lang = None
|
self.lang = None
|
||||||
|
|
||||||
self.story = story
|
self.story = story
|
||||||
self.story.MOVE = move
|
self.story.MOVE = True
|
||||||
|
|
||||||
self.test = test
|
self.test = test
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
|
@ -71,8 +70,7 @@ class Statemachine:
|
||||||
State.IDLE_END: self._idle_end
|
State.IDLE_END: self._idle_end
|
||||||
}
|
}
|
||||||
|
|
||||||
while (self.state is not State.ERROR) and \
|
while (self.state is not State.ERROR) and (self.state is not State.SHUTDOWN):
|
||||||
(self.state is not State.SHUTDOWN):
|
|
||||||
logger.debug(f'Run(state={self.state})')
|
logger.debug(f'Run(state={self.state})')
|
||||||
try:
|
try:
|
||||||
choice[self.state]()
|
choice[self.state]()
|
||||||
|
@ -185,22 +183,24 @@ class Statemachine:
|
||||||
turn_off(self.hal)
|
turn_off(self.hal)
|
||||||
self.story.skip_flag = False
|
self.story.skip_flag = False
|
||||||
self.story.rewind()
|
self.story.rewind()
|
||||||
|
self._next_state()
|
||||||
if self.loop:
|
|
||||||
self.state = State.IDLE_START
|
|
||||||
else:
|
|
||||||
self._next_state()
|
|
||||||
|
|
||||||
def _idle_end(self):
|
def _idle_end(self):
|
||||||
"""
|
"""
|
||||||
Initialize shutdown
|
Initialize shutdown or go back to POST if `self.loop=True`
|
||||||
"""
|
"""
|
||||||
self._next_state()
|
reset(self.hal)
|
||||||
|
self.hal.helo1 = False
|
||||||
|
|
||||||
|
if self.loop:
|
||||||
|
self.state = State.POST
|
||||||
|
else:
|
||||||
|
self._next_state()
|
||||||
|
|
||||||
def _shutdown(self):
|
def _shutdown(self):
|
||||||
"""
|
"""
|
||||||
Clean up, end execution
|
Clean up, end execution
|
||||||
"""
|
"""
|
||||||
self.hal.pin_helo1.off()
|
|
||||||
del self.hal
|
del self.hal
|
||||||
del self.story
|
del self.story
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,11 @@ class Option(Enum):
|
||||||
"""
|
"""
|
||||||
Options can be chosen by the user in WAIT_FOR_INPUT
|
Options can be chosen by the user in WAIT_FOR_INPUT
|
||||||
"""
|
"""
|
||||||
CONTINUE = {'skip_flag': False} # Continue with chapter. Set `skip_flag=True` to skip all chapters marked with `skip_flag`
|
CONTINUE = {'skip_flag': None} # Continue with chapter. Set `skip_flag=True` to skip all chapters marked with `skip_flag`
|
||||||
REPEAT = {'rewind': True} # Repeat chapter from beginning. `rewind=True`: reset scrolls to starting position
|
REPEAT = {'rewind': True} # Repeat chapter from beginning. `rewind=True`: reset scrolls to starting position
|
||||||
GOTO = {'chapter': 0} # Jump to chapter number
|
GOTO = {'chapter': 0,
|
||||||
QUIT = {'quit': True} # End playback.
|
'skip_flag': None} # Jump to chapter number
|
||||||
|
QUIT = {} # End playback. Will cause restart if `statemachine.loop=True`
|
||||||
|
|
||||||
|
|
||||||
class Select:
|
class Select:
|
||||||
|
@ -65,10 +66,10 @@ class Activity(Enum):
|
||||||
RECORD_VIDEO = {'duration': 60.0,
|
RECORD_VIDEO = {'duration': 60.0,
|
||||||
'filename': ''}
|
'filename': ''}
|
||||||
TAKE_PHOTO = {'filename': ''}
|
TAKE_PHOTO = {'filename': ''}
|
||||||
ADVANCE_UP = {'steps': 46,
|
ADVANCE_UP = {'steps': 48,
|
||||||
'scroll': Scrolls.VERTICAL,
|
'scroll': Scrolls.VERTICAL,
|
||||||
'speed': 3}
|
'speed': 3}
|
||||||
ADVANCE_LEFT = {'steps': 96,
|
ADVANCE_LEFT = {'steps': 92,
|
||||||
'scroll': Scrolls.HORIZONTAL,
|
'scroll': Scrolls.HORIZONTAL,
|
||||||
'speed': 3}
|
'speed': 3}
|
||||||
LIGHT_FRONT = {'r': 0,
|
LIGHT_FRONT = {'r': 0,
|
||||||
|
@ -211,7 +212,7 @@ class Storyboard:
|
||||||
|
|
||||||
self.skip_flag = False # Set `True` to skip chapters marked with skip_flag
|
self.skip_flag = False # Set `True` to skip chapters marked with skip_flag
|
||||||
|
|
||||||
self.MOVE = False # self.move is reset to this value
|
self.MOVE = True # self.move is reset to this value
|
||||||
self._move = self.MOVE
|
self._move = self.MOVE
|
||||||
|
|
||||||
self._lang = Language.NOT_SET
|
self._lang = Language.NOT_SET
|
||||||
|
@ -255,39 +256,40 @@ class Storyboard:
|
||||||
Return a callback for the appropriate option and parameters.
|
Return a callback for the appropriate option and parameters.
|
||||||
Callbacks set the properties of `Statemachine` to determine it's behaviour.
|
Callbacks set the properties of `Statemachine` to determine it's behaviour.
|
||||||
"""
|
"""
|
||||||
# rewind = selection.values.get('rewind', Option.REPEAT.value['rewind'])
|
_rewind = selection.values.get('rewind', None)
|
||||||
# next_chapter = selection.values.get('chapter', Option.GOTO.value['chapter'])
|
_next_chapter = selection.values.get('chapter', None)
|
||||||
# shutdown = selection.values.get('shutdown', Option.QUIT.value['shutdown'])
|
|
||||||
_skip_flag = selection.values.get('skip_flag', None)
|
_skip_flag = selection.values.get('skip_flag', None)
|
||||||
if _skip_flag is not None:
|
|
||||||
self.skip_flag = _skip_flag
|
|
||||||
|
|
||||||
def _continue(**kwargs):
|
def _continue():
|
||||||
"""
|
"""
|
||||||
Continue in the Storyboard. Prepare advancing to the next chapter.
|
Continue in the Storyboard. Prepare advancing to the next chapter.
|
||||||
"""
|
"""
|
||||||
logger.debug('User selected continue')
|
logger.debug('User selected continue')
|
||||||
if len(self.story) > (self._index + 1):
|
if len(self.story) > (self._index + 1):
|
||||||
self.next_chapter = self._index + 1
|
self.next_chapter = self._index + 1
|
||||||
|
if _skip_flag is not None:
|
||||||
|
self.skip_flag = _skip_flag
|
||||||
else:
|
else:
|
||||||
self.next_chapter = None
|
self.next_chapter = None
|
||||||
|
|
||||||
def _repeat(rewind: bool=None, **kwargs):
|
def _repeat():
|
||||||
"""
|
"""
|
||||||
Repeat the current chapter. Do not rewind if the selection says so.
|
Repeat the current chapter. Do not rewind if the selection says so.
|
||||||
"""
|
"""
|
||||||
logger.debug('User selected repeat')
|
logger.debug('User selected repeat')
|
||||||
self.next_chapter = self._index
|
self.next_chapter = self._index
|
||||||
self.move = rewind
|
self.move = _rewind
|
||||||
|
|
||||||
def _goto(chapter: int=None, **kwargs):
|
def _goto():
|
||||||
"""
|
"""
|
||||||
Jump to a specified chapter.
|
Jump to a specified chapter.
|
||||||
"""
|
"""
|
||||||
logger.debug(f'User selected goto {chapter}')
|
logger.debug(f'User selected goto {_next_chapter}')
|
||||||
self.next_chapter = chapter
|
self.next_chapter = _next_chapter
|
||||||
|
if _skip_flag is not None:
|
||||||
|
self.skip_flag = _skip_flag
|
||||||
|
|
||||||
def _quit(**kwargs):
|
def _quit():
|
||||||
logger.debug('User selected quit')
|
logger.debug('User selected quit')
|
||||||
self.next_chapter = None
|
self.next_chapter = None
|
||||||
|
|
||||||
|
@ -346,6 +348,8 @@ class Storyboard:
|
||||||
|
|
||||||
def _move(hal, do_now=True, **kwargs):
|
def _move(hal, do_now=True, **kwargs):
|
||||||
logger.debug(f'Storyboard._move({kwargs})')
|
logger.debug(f'Storyboard._move({kwargs})')
|
||||||
|
if not self.move:
|
||||||
|
return
|
||||||
set_movement(hal, **kwargs)
|
set_movement(hal, **kwargs)
|
||||||
if do_now:
|
if do_now:
|
||||||
do_it(hal)
|
do_it(hal)
|
||||||
|
@ -421,12 +425,12 @@ class Storyboard:
|
||||||
steps = ch.rewind()
|
steps = ch.rewind()
|
||||||
h_steps += steps['h_steps']
|
h_steps += steps['h_steps']
|
||||||
v_steps += steps['v_steps']
|
v_steps += steps['v_steps']
|
||||||
|
|
||||||
elif diff > 0:
|
elif diff > 0:
|
||||||
"""
|
"""
|
||||||
Skip all chapters up to target
|
Skip all chapters up to target
|
||||||
"""
|
"""
|
||||||
for ch in self.story[self._index:self._next_chapter]:
|
for ch in self.story[self._index:self._next_chapter]:
|
||||||
|
logger.debug(f'Queueing chapter {ch} for skipping')
|
||||||
steps = ch.skip()
|
steps = ch.skip()
|
||||||
h_steps += steps['h_steps']
|
h_steps += steps['h_steps']
|
||||||
v_steps += steps['v_steps']
|
v_steps += steps['v_steps']
|
||||||
|
@ -438,6 +442,7 @@ class Storyboard:
|
||||||
h_steps = steps['h_steps']
|
h_steps = steps['h_steps']
|
||||||
v_steps = steps['v_steps']
|
v_steps = steps['v_steps']
|
||||||
|
|
||||||
|
logger.debug(f'storyboard.move={self.move} and h_steps={h_steps}, v_steps={v_steps}.')
|
||||||
if self.move and ((h_steps != 0) or (v_steps != 0)):
|
if self.move and ((h_steps != 0) or (v_steps != 0)):
|
||||||
set_movement(self.hal, scroll=Scrolls.HORIZONTAL, steps=h_steps, speed=4)
|
set_movement(self.hal, scroll=Scrolls.HORIZONTAL, steps=h_steps, speed=4)
|
||||||
set_movement(self.hal, scroll=Scrolls.VERTICAL, steps=v_steps, speed=4)
|
set_movement(self.hal, scroll=Scrolls.VERTICAL, steps=v_steps, speed=4)
|
||||||
|
|
Loading…
Reference in a new issue