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
18 changes: 18 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Host tests

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Check Python syntax
run: python -m compileall -q .
- name: Run host-side tests
run: python -m unittest discover -s tests -v
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
*.py[cod]
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,22 @@ The instructions enable the software on the required hardware. These instructi
* Copy the .py files
* Copy the uf2 file, the Pico should restart, and the timer automatically starts.

## Configuration files

Version 3.2 uses two separate configuration scopes:

* `params.json` contains system-owned choices and display behavior: `DURATION_VALUES`, `LAUNCH_SENSE_VALUES`, `VERSION`, `DISPLAY_DELAY_REST`, `DISPLAY_DELAY_REST_COLOUR`, and `BOOT_DELAY_SEC`.
* `user.json` contains the current user selections: `RACE_LENGTH` (track-session minutes), `REST_LENGTH` (pit-rest minutes), and `SENSITIVITY` (launch threshold; `0` disables Launch Mode).

The firmware has built-in system and user defaults. Missing, malformed, or unsupported user values are replaced with safe defaults and saved using the canonical keys above. Existing `TRACK_LENGTH`, `TRACK_SESSION_LENGTH`, and `REST_SESSION_LENGTH` user keys are migrated automatically.

## Host-side tests

Run the hardware-independent regression suite with:

```sh
python -m unittest discover -s tests -v
```

The suite uses fakes for time, touch gestures, display calls, filesystem operations, and accelerometer samples. It does not validate physical SPI/I2C wiring, LCD rendering, touchscreen recognition, QMI8658 readings, or real-world launch thresholds; those behaviors still require the selected target hardware.

9 changes: 5 additions & 4 deletions User Guide.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# User Guide -v3.1
# User Guide - v3.2

## General / Sessions Use
The following describes general operation of both the ``Track Session`` and ``Rest in Pits Session`` timer.
Expand All @@ -14,8 +14,8 @@ The following describes general operation of both the ``Track Session`` and ``Re
* Following termination, a ``Rest in Pits`` splash will display, followed by commencement of the ``Rest in Pits Session`` timer.
* Once the ``Rest in Pits Session`` is complete, the timer will return to the ``Primary screen``. The ``Rest in Pits Session`` can be terminated with a ``Double Tap``.

## Configuration / Setup
All settings are stored from session to session while the timer has power. Settings are wiped if power is lost.
## Configuration / Setup
Track duration, rest duration, and launch sensitivity are saved to `user.json` when changed. These settings persist across restarts and power loss. If the file is missing, damaged, or contains unsupported values, the timer restores safe defaults and rewrites the file using the canonical v3.2 setting names.

### Session Duration
It is possible to change the duration of both the ``Track Session`` and the ``Rest in Pits``.
Expand All @@ -29,4 +29,5 @@ It is possible to change the duration of both the ``Track Session`` and the ``Re
``Launch mode`` can be enabled by defining a ``Launch Sensitivity`` value above zero.
* From the ``Primary Screen``, ``Swipe Up`` to edit ``Launch Sensitivity``.
* Swipe ``Left`` or ``Right`` to select an appropriate value greater than zero.
* Swip ``UP`` to save and enable ``Launch mode``
* Swipe ``UP`` to save and enable ``Launch mode``.
* Select `0` and swipe ``UP`` to save and disable ``Launch mode``.
67 changes: 67 additions & 0 deletions configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Touch-driven configuration editors with injected display dependencies."""


def _selected_index(values, current):
if not values:
raise ValueError("At least one selectable value is required")
try:
return values.index(current)
except ValueError:
return 0


def set_sensitivity(LCD=None, Touch=None, sensitivity_values=None, sensitivity=0,
operation="Config", back_colour="palegreen"):
"""Select launch sensitivity, starting from the current saved value."""
values = list(sensitivity_values or [])
index = _selected_index(values, sensitivity)

def draw():
text_array = [
[str(values[index]), 60, 80, 5, "white"],
["Launch", 75, 150, 2, "black"],
["Sensitivity", 20, 180, 2, "black"],
[operation, 75, 35, 2, "black"],
]
Touch.ControlScreen(LCD, text_array=text_array, back_colour=back_colour)

draw()
while True:
gesture = Touch.GetGesture(LCD)
if gesture == "up":
return values[index]
if gesture == "left":
index = (index - 1) % len(values)
draw()
elif gesture == "right":
index = (index + 1) % len(values)
draw()


def set_session(LCD=None, Touch=None, session=None, session_values=None,
session_name=None, operation="Config", back_colour="palegreen"):
"""Select a session duration, starting from the session's current value."""
values = list(session_values or [])
current = getattr(session, "duration_mins", None)
index = _selected_index(values, current)

def draw():
text_array = [
[str(values[index]), 70, 96, 5, "white"],
[session_name, 75, 195, 2, "black"],
[operation, 75, 35, 2, "black"],
]
Touch.ControlScreen(LCD, text_array=text_array, back_colour=back_colour)

draw()
while True:
gesture = Touch.GetGesture(LCD)
if gesture == "up":
session.duration_mins = values[index]
return session.duration_mins
if gesture == "left":
index = (index - 1) % len(values)
draw()
elif gesture == "right":
index = (index + 1) % len(values)
draw()
18 changes: 18 additions & 0 deletions launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Hardware-independent launch wait loop."""


def accel_launch(qmi8658, sensitivity=0):
"""Wait for the existing all-axis threshold condition.

The launch algorithm itself remains tracked by issue #3. Keeping the loop in
this importable module allows deterministic regression tests around it.
"""
ac_x = 0
ac_y = 0
ac_z = 0
while ac_x < sensitivity or ac_y < sensitivity or ac_z < sensitivity:
xyz = qmi8658.Read_XYZ()
ac_x = xyz[0]
ac_y = xyz[1]
ac_z = xyz[2]
return True
Loading
Loading