From a1b11fb1eb8175a50f0398bc1d695dbc7210dec1 Mon Sep 17 00:00:00 2001 From: DamTobor Date: Fri, 31 May 2024 19:47:07 +0100 Subject: [PATCH] Version 0.4.1 (#7) * power is 4 tuple * no standard library * add warning screen --- app.py | 116 ++++++++++++++++++++++++++++---------------------- tildagon.toml | 2 +- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/app.py b/app.py index d9aca9b..8ca6c2a 100644 --- a/app.py +++ b/app.py @@ -1,13 +1,13 @@ -import asyncio -from typing import Iterator, List, Optional, Tuple -from itertools import chain - +from logging import WARN, WARNING import app -from enum import Enum from app_components.tokens import label_font_size from events.input import Buttons, BUTTON_TYPES +# Motor Driver +PWM_FREQ = 5000 +MAX_DUTY = 1023 + VERTICAL_OFFSET = label_font_size H_START = -78 V_START = -58 @@ -20,26 +20,20 @@ MAX_POWER = 100 -class BadgeBotAppState(Enum): - MENU = 1 - RECEIVE_INSTR = 2 - COUNTDOWN = 3 - RUN = 4 - DONE = 5 +# App states +WARNING = 0 +MENU = 1 +RECEIVE_INSTR = 2 +COUNTDOWN = 3 +RUN = 4 +DONE = 5 class Instruction: - # tick - # Each tick update pwm - # target speed - # current speed - # Trapezium, estimate 200ms - def __init__(self, press_type: BUTTON_TYPES) -> None: self._press_type = press_type self._duration = 1 - self.current_power_duration = (0, 0) self.power_plan_iterator = iter([]) @property @@ -52,13 +46,23 @@ def inc(self): def __str__(self): return f"{self.press_type.name} {self._duration}" - - def make_power_plan(self) -> Iterator[Tuple[int, int]]: - # return collection of tuples of durations at each power - ramp_up = [(i, TICK_MS) for i in range(0, MAX_POWER, POWER_STEP_PER_TICK)] + def directional_power_tuple(self, power): + if self._press_type == BUTTON_TYPES["UP"]: + return (power, 0, power, 0) + elif self._press_type == BUTTON_TYPES["DOWN"]: + return (0, power, 0, power) + elif self._press_type == BUTTON_TYPES["LEFT"]: + return (power, 0, 0, power) + elif self._press_type == BUTTON_TYPES["RIGHT"]: + return (0, power, power, 0) + + def make_power_plan(self): + # return collection of tuples of power and their duration + ramp_up = [(self.directional_power_tuple(p), TICK_MS) + for p in range(0, MAX_POWER, POWER_STEP_PER_TICK)] power_durations = ramp_up.copy() user_power_duration = TICK_MS * USER_TICK_MULTIPLIER * (self._duration-1) - power_durations.append((MAX_POWER, user_power_duration)) + power_durations.append((self.directional_power_tuple(MAX_POWER), user_power_duration)) ramp_down = ramp_up.copy() ramp_down.reverse() power_durations.extend(ramp_down) @@ -71,8 +75,6 @@ def __init__(self): self.last_press: BUTTON_TYPES = BUTTON_TYPES["CANCEL"] self.long_press_delta = 0 - self.power = 0 - self.is_scroll = False self.scroll_offset = 0 @@ -82,11 +84,11 @@ def __init__(self): self.instructions = [] self.current_instruction = None - self.current_power_duration = (0, 0) + self.current_power_duration = ((0,0,0,0), 0) self.power_plan_iter = iter([]) # Overall app state - self.current_state = BadgeBotAppState.MENU + self.current_state = WARNING def update(self, delta): if self.button_states.get(BUTTON_TYPES["CANCEL"]): @@ -96,14 +98,19 @@ def update(self, delta): self.button_states.clear() self.minimise() - if self.current_state == BadgeBotAppState.MENU: + if self.current_state == MENU: # Exit start menu if self.button_states.get(BUTTON_TYPES["CONFIRM"]): - self.current_state = BadgeBotAppState.RECEIVE_INSTR + self.current_state = RECEIVE_INSTR self.button_states.clear() + elif self.current_state == WARNING: + # Exit warning screen + if self.button_states.get(BUTTON_TYPES["CONFIRM"]): + self.current_state = MENU + self.button_states.clear() - elif self.current_state == BadgeBotAppState.RECEIVE_INSTR: + elif self.current_state == RECEIVE_INSTR: # Enable/disable scrolling and check for long press if self.button_states.get(BUTTON_TYPES["CONFIRM"]): @@ -113,7 +120,7 @@ def update(self, delta): self.long_press_delta += delta if self.long_press_delta >= LONG_PRESS_MS: self.finalize_instruction() - self.current_state = BadgeBotAppState.COUNTDOWN + self.current_state = COUNTDOWN else: # Confirm is not pressed. Reset long_press state @@ -141,19 +148,20 @@ def update(self, delta): self._handle_instruction_press(BUTTON_TYPES["DOWN"]) self.button_states.clear() - elif self.current_state == BadgeBotAppState.COUNTDOWN: + elif self.current_state == COUNTDOWN: self.run_countdown_ms += delta if self.run_countdown_ms >= self.run_countdown_target_ms: - self.power_plan_iter = chain(*(instr.power_plan_iterator for instr in self.instructions)) - self.current_state = BadgeBotAppState.RUN + self.power_plan_iter = self.instructions[0].power_plan_iterator # TODO chain all instr + self.current_state = RUN - elif self.current_state == BadgeBotAppState.RUN: - self.power = self.get_current_power_level(delta) - print(f"Using power: {self.power}") - if self.power is None: - self.current_state = BadgeBotAppState.DONE + elif self.current_state == RUN: + print(delta) + power = self.get_current_power_level(delta) + if power is None: + self.current_state = DONE + print(f"Using power: {power}") - elif self.current_state == BadgeBotAppState.DONE: + elif self.current_state == DONE: if self.button_states.get(BUTTON_TYPES["CONFIRM"]): self.reset() @@ -166,13 +174,11 @@ def _handle_instruction_press(self, press_type: BUTTON_TYPES): self.last_press = press_type def reset(self): - self.current_state = BadgeBotAppState.MENU + self.current_state = MENU self.button_states.clear() self.last_press: BUTTON_TYPES = BUTTON_TYPES["CANCEL"] self.long_press_delta = 0 - self.power = 0 - self.is_scroll = False self.scroll_offset = 0 @@ -182,7 +188,7 @@ def reset(self): self.instructions = [] self.current_instruction = None - self.current_power_duration = (0, 0) + self.current_power_duration = ((0,0,0,0), 0) self.power_plan_iter = iter([]) @@ -195,29 +201,35 @@ def draw(self, ctx): else: ctx.rgb(0,0,0.1).rectangle(-120,-120,240,240).fill() - if self.current_state == BadgeBotAppState.MENU: + if self.current_state == WARNING: + ctx.rgb(1,1,1).move_to(H_START, V_START + 0*VERTICAL_OFFSET + 20).text("Please buy") + ctx.rgb(1,1,1).move_to(H_START, V_START + 1*VERTICAL_OFFSET + 20).text("BadgeBot") + ctx.rgb(1,1,0).move_to(H_START, V_START + 2*VERTICAL_OFFSET + 20).text("Hexpansion") + ctx.rgb(1,1,0).move_to(H_START, V_START + 3*VERTICAL_OFFSET + 20).text("from") + ctx.rgb(1,1,0).move_to(H_START, V_START + 4*VERTICAL_OFFSET + 20).text("RobotMad") + elif self.current_state == MENU: ctx.rgb(1,1,1).move_to(H_START, V_START).text("To Program:") ctx.rgb(1,1,0).move_to(H_START, V_START + VERTICAL_OFFSET).text("Press C") ctx.rgb(1,1,1).move_to(H_START, V_START + 2*VERTICAL_OFFSET + 10).text("When finished:") ctx.rgb(1,1,0).move_to(H_START, V_START + 3*VERTICAL_OFFSET + 10).text("Long press C") - elif self.current_state == BadgeBotAppState.RECEIVE_INSTR: + elif self.current_state == RECEIVE_INSTR: for i_num, instr in enumerate(["START"] + self.instructions + [self.current_instruction, "END"]): ctx.rgb(1,1,0).move_to(H_START, V_START + VERTICAL_OFFSET * (self.scroll_offset + i_num)).text(str(instr)) - elif self.current_state == BadgeBotAppState.COUNTDOWN: + elif self.current_state == COUNTDOWN: ctx.rgb(1,1,1).move_to(H_START, V_START).text("Running in:") countdown_val = (self.run_countdown_target_ms - self.run_countdown_ms) / 1000 ctx.rgb(1,1,0).move_to(H_START, V_START+VERTICAL_OFFSET).text(countdown_val) - elif self.current_state == BadgeBotAppState.RUN: - ctx.rgb(1,0,0).move_to(H_START, V_START).text("Running power") - ctx.rgb(0,0,1).move_to(H_START, V_START + VERTICAL_OFFSET).text(str(self.power)) - elif self.current_state == BadgeBotAppState.DONE: + elif self.current_state == RUN: + ctx.rgb(1,1,1).move_to(H_START, V_START).text("Running power") + ctx.rgb(1,0,0).move_to(H_START, V_START + 2*VERTICAL_OFFSET).text(str(self.current_power_duration)) + elif self.current_state == DONE: ctx.rgb(1,1,1).move_to(H_START, V_START).text(f"Complete!") ctx.rgb(1,1,1).move_to(H_START, V_START + VERTICAL_OFFSET).text("To restart:") ctx.rgb(1,1,0).move_to(H_START, V_START + 2*VERTICAL_OFFSET).text("Press C") ctx.restore() - def get_current_power_level(self, delta) -> Optional[int]: + def get_current_power_level(self, delta) -> int: # takes in delta as ms since last call # if delta was > 20... what to do if delta >= TICK_MS: diff --git a/tildagon.toml b/tildagon.toml index 12ad9f2..22f3b7d 100644 --- a/tildagon.toml +++ b/tildagon.toml @@ -37,4 +37,4 @@ description = "A demo tildagon app for use with Hex Drive hexpansion " # increased, we interpret this as a new version being released. # # Version number must be an integer! -version = "0.4.0" +version = "0.4.1"