Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ The second command should identify an RP2040 MicroPython board.
Run these commands from the repository root. Supporting files and font assets are copied first; `main.py` is installed last as the automatic entry point.

```sh
mpremote connect auto fs cp configuration.py font_data.py font_renderer.py hardware.py launch.py lcd_1inch28.py live_display.py params.json qmi8658.py settings.py splash.py timing.py touch_drive.py font_data*.bin startup_splash.rgb565 :
mpremote connect auto fs cp configuration.py font_data.py font_renderer.py hardware.py launch.py lcd_1inch28.py live_display.py params.json qmi8658.py ready_screen.py settings.py splash.py timing.py touch_drive.py font_data*.bin startup_splash.rgb565 :
mpremote connect auto fs cp main.py :
mpremote connect auto reset
```
Expand Down
2 changes: 1 addition & 1 deletion User Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
The following describes general operation of both the ``Track Session`` and ``Rest in Pits Session`` timer.

* Upon start up a boot splash will be shown for 2 seconds.
* After which the ``Primary Screen`` will be shown, detailing the current track session duration in minutes, and the statement ``Ready``. This indicates the timer is ready to start. To start the ``Track Session`` or race, ``Swipe Down``.
* After which the ``Primary Screen`` will show ``Ready`` together with the saved track duration, rest duration, and effective Launch Mode state. ``Launch unavailable`` means the saved non-zero sensitivity could not be used because the IMU is unavailable; normal swipe-down timing still works. To start the ``Track Session`` or race, ``Swipe Down``.
* After swiping down, ``Go`` will display briefly. If ``Launch Mode`` has been activated, ``Lights`` will be displayed while the timer measures a stationary baseline and waits for sufficient acceleration.
* While waiting in ``Launch Mode``, double-tap to cancel and return to the ``Primary Screen``. The wait also cancels automatically after 30 seconds.
* Upon starting, the ``Track Session`` timer count down will be displayed, and immediately commence.
Expand Down
17 changes: 11 additions & 6 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
track_live_frame,
)
from qmi8658 import QMI8658
from ready_screen import ready_screen_lines
from settings import load_configuration, persist_setting
from timing import SessionTracker
from touch_drive import Touch_CST816T
Expand All @@ -29,10 +30,6 @@
USER_FILE = "user.json"

PIT_SESSION_MSG = ["Cool down!", "Rest in pits"]
TRACK_SESSION_MSG = ["Ready", "Swipe DOWN to start"]
CLINE1 = [TRACK_SESSION_MSG[0], None, 90, 5, "white"]
CLINE2 = [TRACK_SESSION_MSG[1], None, 185, 1, "black"]
CLINE3 = ["message", None, 35, 3, "black"]
PLINE1 = [PIT_SESSION_MSG[0], None, 88, 3, "white"]
PLINE2 = [PIT_SESSION_MSG[1], None, 145, 2, "red"]

Expand Down Expand Up @@ -102,8 +99,16 @@ def main():
rest_session = SessionTracker(duration_mins=rest_length, stype="rest", debug=True)

while not launch:
CLINE3[0] = str(track_session.duration_mins) + "mins"
touch.ControlScreen(lcd, text_array=[CLINE1, CLINE2, CLINE3], back_colour="green")
touch.ControlScreen(
lcd,
text_array=ready_screen_lines(
track_minutes=track_session.duration_mins,
rest_minutes=rest_session.duration_mins,
sensitivity=configured_sensitivity,
imu_available=qmi8658 is not None,
),
back_colour="green",
)
gesture = touch.GetGesture(lcd)

if gesture == "left":
Expand Down
33 changes: 33 additions & 0 deletions ready_screen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Ready-screen settings summary independent of display hardware."""


def _format_sensitivity(sensitivity):
numeric = float(sensitivity)
if numeric == int(numeric):
return str(int(numeric))
return str(numeric)


def launch_status(sensitivity, imu_available):
"""Return the effective Launch Mode state shown before a session."""
if float(sensitivity) <= 0:
return "Launch OFF"
if not imu_available:
return "Launch unavailable"
return "Launch {}g".format(_format_sensitivity(sensitivity))


def ready_screen_lines(
track_minutes,
rest_minutes,
sensitivity,
imu_available,
):
"""Build the complete Ready screen text layout."""
return [
["Ready", None, 38, 4, "white"],
["Track {}m".format(track_minutes), None, 100, 2, "black"],
["Rest {}m".format(rest_minutes), None, 130, 2, "black"],
[launch_status(sensitivity, imu_available), None, 160, 2, "black"],
["Swipe DOWN to start", None, 205, 1, "black"],
]
42 changes: 42 additions & 0 deletions tests/test_ready_screen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import math
import unittest

from font_renderer import measure_text, pixel_height
from ready_screen import launch_status, ready_screen_lines


class ReadyScreenTests(unittest.TestCase):
def test_summary_contains_all_saved_settings_and_start_action(self):
lines = ready_screen_lines(20, 15, 0.5, True)

self.assertEqual(
[
"Ready",
"Track 20m",
"Rest 15m",
"Launch 0.5g",
"Swipe DOWN to start",
],
[line[0] for line in lines],
)

def test_launch_status_reflects_effective_mode(self):
self.assertEqual("Launch OFF", launch_status(0, False))
self.assertEqual("Launch 1g", launch_status(1, True))
self.assertEqual("Launch unavailable", launch_status(1.25, False))

def test_every_line_fits_inside_the_round_display(self):
display_radius = 120
widest_values = ready_screen_lines(60, 60, 1.75, False)

for text, _, y_position, size, _ in widest_values:
text_center_y = y_position + (pixel_height(size) / 2)
distance_from_center = text_center_y - display_radius
visible_width = 2 * math.sqrt(
(display_radius ** 2) - (distance_from_center ** 2)
)
self.assertLessEqual(measure_text(text, size), visible_width)


if __name__ == "__main__":
unittest.main()
Loading