Skip to content
Open
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 .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
make dist

- name: Upload Packages
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_FILE }}
path: dist/
55 changes: 55 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Contributing

## Development environment

A Docker-based testing image is provided so checks can be run against multiple Python versions
without installing tooling locally. Python 3.11 is the first version set up; others will follow.

### Build the image

Pass your host UID and GID so that files written inside the container are owned by your user,
not root:

```bash
docker build -f Dockerfile.testing \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
-t inventorhatmini-dev:python3.11-v1.0.1 .
```

> **Image tag convention:** `inventorhatmini-dev:python<python-ver>-v<testing-ver>`
> The testing version is always at least one patch ahead of the released library version
> (e.g. library `1.0.0` → testing image `v1.0.1`).

### Run checks

All commands below mount the repository into the container so changes are picked up without
a rebuild. Run them from the repository root.

**Integrity checks** (trailing whitespace, DOS line-endings, CHANGELOG entry, git tag):

```bash
docker run --rm -v "$(pwd)":/app inventorhatmini-dev:python3.11-v1.0.1 make check
```

**Shell script linting:**

```bash
docker run --rm -v "$(pwd)":/app inventorhatmini-dev:python3.11-v1.0.1 make shellcheck
```

**QA** (ruff, isort, codespell, check-manifest, build, twine check):

```bash
docker run --rm -v "$(pwd)":/app inventorhatmini-dev:python3.11-v1.0.1 make qa
```

### Dependency lock file

The image installs from `requirements-dev.lock`. Regenerate it when `requirements-dev.txt` changes:

```bash
uv pip compile requirements-dev.txt --output-file requirements-dev.lock --python-version 3.11
```

Then rebuild the image.
52 changes: 52 additions & 0 deletions Dockerfile.testing
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# syntax=docker/dockerfile:1
#
# Tagging convention: inventorhatmini-dev:python<python-ver>-v<testing-ver>
# python-ver — Python minor version in the base image (e.g. 3.11)
# testing-ver — SemVer, always at least one patch ahead of the released
# inventorhatmini library version (e.g. library 1.0.0 → testing v1.0.1)
#
# Build example:
# docker build -f Dockerfile.testing -t inventorhatmini-dev:python3.11-v1.0.1 .
#
# Stage 1: UV binary source
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv-base

# Stage 2: Testing environment
FROM python:3.11-slim-bookworm AS testing

# Copy UV binary from uv-base stage
COPY --from=uv-base /uv /uvx /usr/local/bin/

# Install system dependencies
# hadolint ignore=DL3008
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
make \
dos2unix \
shellcheck \
git \
&& rm -rf /var/lib/apt/lists/*

# Create a non-root user matching typical host UID/GID (1000:1000).
# Override at runtime with: --user $(id -u):$(id -g)
ARG UID=1000
ARG GID=1000
RUN groupadd -g "${GID}" appuser \
&& useradd -l -u "${UID}" -g "${GID}" -m appuser

WORKDIR /app

# Copy dependency lock file first for layer caching
COPY requirements-dev.lock ./

# Install dev dependencies from pinned lock file
RUN uv pip install --system --no-cache -r requirements-dev.lock

# Copy project source
COPY . .

USER appuser

# Allow git to read the volume-mounted repo (ownership matches host UID but
# git's safe.directory check still fires on mounted directories).
RUN git config --global --add safe.directory /app
1 change: 1 addition & 0 deletions check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ LIBRARY_NAME=$(hatch project metadata name)
LIBRARY_VERSION=$(hatch version | awk -F "." '{print $1"."$2"."$3}')
POST_VERSION=$(hatch version | awk -F "." '{print substr($4,0,length($4))}')
TERM=${TERM:="xterm-256color"}
export TERM

success() {
echo -e "$(tput setaf 2)$1$(tput sgr0)"
Expand Down
9 changes: 3 additions & 6 deletions firmware/firmware_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
# Usage: python firmware_update.py filename.hex

import binascii

import sys
import time


from smbus2 import SMBus, i2c_msg


# Small nuvoton:
bootloader_id = 0xB001
bootloader_version = 172
Expand Down Expand Up @@ -108,7 +105,7 @@ def write_page_to_aprom():
try:
i2c_read8(bootloader_i2c_addr, 0x00)
break
except:
except Exception:
print("waiting for page write to finish...")

def read_page_from_aprom():
Expand All @@ -126,7 +123,7 @@ def firmware_update(bin_data, i2c_address, chip_id):

try:
i2c_read8(bootloader_i2c_addr, 0x00)
except:
except Exception:
# We're not in bootloader yet, let's enter first
confirm_id(i2c_address, chip_id)
enter_bootloader(i2c_address)
Expand Down Expand Up @@ -187,7 +184,7 @@ def firmware_update(bin_data, i2c_address, chip_id):


if __name__ == "__main__":
filename = sys.argv[1];
filename = sys.argv[1]
# if bin_filename.endswith(".bin"):
# bin_data = open(bin_filename, "rb").read()
# bin_data = [ord(x) for x in bin_data]
Expand Down
43 changes: 21 additions & 22 deletions firmware/set_i2c_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
# flash write ongoing
# flash write ongoing
# flash write finished
# pi@raspberrypi:~ $
# pi@raspberrypi:~ $
# pi@raspberrypi:~ $
# pi@raspberrypi:~ $
# pi@raspberrypi:~ $ i2cdetect -y 1
# 0 1 2 3 4 5 6 7 8 9 a b c d e f
# 00: -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- 22 -- -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --
# 00: -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- 22 -- -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --
# pi@raspberrypi:~ $ python set_i2c_address.py 0x22 0x23
# Waiting for flash writing to start..
# flash write ongoing
Expand All @@ -33,26 +33,25 @@
# flash write finished
# pi@raspberrypi:~ $ i2cdetect -y 1
# 0 1 2 3 4 5 6 7 8 9 a b c d e f
# 00: -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --
# 00: -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --

import time
import os
import sys
import time

import RPi.GPIO as GPIO
from smbus2 import SMBus, i2c_msg

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

CHIP_ID = 0xBA11
VERSION = 1
VERSION = 1


# Registers specific to the trackball
Expand Down
Loading
Loading