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
66 changes: 66 additions & 0 deletions .github/scripts/build-dfu-util-macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -euo pipefail

readonly DFU_UTIL_VERSION="0.11"
readonly DFU_UTIL_SHA256="b4b53ba21a82ef7e3d4c47df2952adf5fa494f499b6b0b57c58c5d04ae8ff19e"
readonly DFU_UTIL_URL="https://dfu-util.sourceforge.net/releases/dfu-util-${DFU_UTIL_VERSION}.tar.gz"
readonly LIBUSB_VERSION="1.0.30"
readonly LIBUSB_SHA256="fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf"
readonly LIBUSB_URL="https://github.com/libusb/libusb/releases/download/v${LIBUSB_VERSION}/libusb-${LIBUSB_VERSION}.tar.bz2"
readonly TARGET_TRIPLE="aarch64-apple-darwin"
readonly ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
readonly WORK_DIR="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/touch-manager-dfu-util"
readonly ARCHIVE="${WORK_DIR}/dfu-util-${DFU_UTIL_VERSION}.tar.gz"
readonly LIBUSB_ARCHIVE="${WORK_DIR}/libusb-${LIBUSB_VERSION}.tar.bz2"
readonly SOURCE_DIR="${WORK_DIR}/dfu-util-${DFU_UTIL_VERSION}"
readonly LIBUSB_SOURCE_DIR="${WORK_DIR}/libusb-${LIBUSB_VERSION}"
readonly LIBUSB_PREFIX="${WORK_DIR}/libusb-static"
readonly OUTPUT_DIR="${ROOT_DIR}/src-tauri/binaries"
readonly OUTPUT="${OUTPUT_DIR}/dfu-util-${TARGET_TRIPLE}"
readonly SOURCE_ASSET_DIR="${ROOT_DIR}/release-assets"

if [[ "$(uname -m)" != "arm64" ]]; then
echo "The Apple Silicon release helper must run on an arm64 macOS runner." >&2
exit 1
fi

rm -rf "${WORK_DIR}"
mkdir -p "${WORK_DIR}" "${OUTPUT_DIR}" "${SOURCE_ASSET_DIR}"

curl --fail --location --retry 3 --silent --show-error "${DFU_UTIL_URL}" --output "${ARCHIVE}"
echo "${DFU_UTIL_SHA256} ${ARCHIVE}" | shasum -a 256 --check
curl --fail --location --retry 3 --silent --show-error "${LIBUSB_URL}" --output "${LIBUSB_ARCHIVE}"
echo "${LIBUSB_SHA256} ${LIBUSB_ARCHIVE}" | shasum -a 256 --check
tar -xzf "${ARCHIVE}" -C "${WORK_DIR}"
tar -xjf "${LIBUSB_ARCHIVE}" -C "${WORK_DIR}"

cd "${LIBUSB_SOURCE_DIR}"
./configure --disable-shared --enable-static --prefix="${LIBUSB_PREFIX}"
make -j"$(sysctl -n hw.logicalcpu)"
make install

cd "${SOURCE_DIR}"
USB_CFLAGS="-I${LIBUSB_PREFIX}/include/libusb-1.0" \
USB_LIBS="${LIBUSB_PREFIX}/lib/libusb-1.0.a -framework IOKit -framework CoreFoundation -framework Security" \
./configure --disable-silent-rules
make -j"$(sysctl -n hw.logicalcpu)"

install -m 0755 src/dfu-util "${OUTPUT}"
strip "${OUTPUT}"
# Tauri copies sidecars into the Cargo target directory. Remove any prior copy so a
# rebuilt helper can never be silently replaced by a stale cached executable.
rm -f "${ROOT_DIR}/src-tauri/target/${TARGET_TRIPLE}/release/dfu-util"
"${OUTPUT}" --version
file "${OUTPUT}" | grep -q "Mach-O 64-bit executable arm64"

if otool -L "${OUTPUT}" | grep -E '/(opt/homebrew|usr/local)/|libusb'; then
echo "Bundled dfu-util unexpectedly depends on a non-system dynamic library." >&2
exit 1
fi

install -m 0644 "${ARCHIVE}" "${SOURCE_ASSET_DIR}/dfu-util-${DFU_UTIL_VERSION}.tar.gz"
install -m 0644 "${LIBUSB_ARCHIVE}" "${SOURCE_ASSET_DIR}/libusb-${LIBUSB_VERSION}.tar.bz2"
shasum -a 256 \
"${OUTPUT}" \
"${SOURCE_ASSET_DIR}/dfu-util-${DFU_UTIL_VERSION}.tar.gz" \
"${SOURCE_ASSET_DIR}/libusb-${LIBUSB_VERSION}.tar.bz2"
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
workspaces: src-tauri

- run: npm ci
- run: bash -n .github/scripts/build-dfu-util-macos.sh
- run: npm test
- run: npm run build
- run: cargo fmt --all -- --check
Expand Down
16 changes: 13 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
with:
targets: aarch64-apple-darwin

- name: Build self-contained flashing engine
run: .github/scripts/build-dfu-util-macos.sh

- run: npm ci

- name: Build and publish DMG
Expand All @@ -34,10 +37,17 @@ jobs:
tagName: ${{ github.ref_name }}
releaseName: Touch Manager ${{ github.ref_name }}
releaseBody: |
Apple Silicon development preview.
Self-contained Apple Silicon development preview.

The flashing engine is included; Homebrew and Terminal setup are not required. This build is not Apple-notarized. On first launch, Control-click Touch Manager and choose Open.

This build is not Apple-notarized. On first launch, Control-click Touch Manager and choose Open. Install dfu-util separately with Homebrew before flashing hardware.
Touch Manager includes dfu-util 0.11 under GPL-2.0-or-later and statically linked libusb 1.0.30 under LGPL-2.1-or-later. Their exact corresponding source archives are attached to this release.
prerelease: true
args: --target aarch64-apple-darwin --bundles dmg
args: --target aarch64-apple-darwin --bundles dmg --config src-tauri/tauri.release.conf.json
releaseAssetNamePattern: Touch-Manager_[version]_[arch].[ext]
uploadUpdaterSignatures: false

- name: Upload bundled component source
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${GITHUB_REF_NAME}" release-assets/dfu-util-0.11.tar.gz release-assets/libusb-1.0.30.tar.bz2 --clobber
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ node_modules/
dist/
src-tauri/target/
src-tauri/gen/
src-tauri/binaries/dfu-util-*
release-assets/
*.log
.DS_Store
7 changes: 4 additions & 3 deletions BUILD_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The physical BOOT/RESET path remains the permanent recovery mechanism.
- Detection of runtime CDC, STM32 ROM DFU, and Daisy Bootloader DFU states.
- Safe support for internal, `BOOT_SRAM`, and `BOOT_QSPI` binaries.
- Guided DFU entry and semantic flash progress.
- Guarded `dfu-util` backend with fixed target profiles.
- Guarded, self-contained `dfu-util` backend with fixed target profiles.
- Runtime return detection and contextual handling of the known post-transfer
`get_status` disconnect.
- USB serial diagnostics, searchable console, and exported support transcript.
Expand Down Expand Up @@ -71,8 +71,8 @@ The physical BOOT/RESET path remains the permanent recovery mechanism.
- `catalog`: loads the bundled catalog, resolves local artifacts, and exposes typed
firmware metadata.
- `device`: enumerates USB and serial devices and models runtime/DFU state.
- `flash`: converts approved profiles into fixed `dfu-util` invocations and interprets
progress/results.
- `flash`: resolves the bundled flashing engine, converts approved profiles into fixed
`dfu-util` invocations, and interprets progress/results.
- `diagnostics`: opens CDC serial ports and emits log events to the interface.
- `history`: records attempted and completed installs in SQLite.

Expand Down Expand Up @@ -195,6 +195,7 @@ the flow on a dedicated test Seed, with recovery tested after interruption.

### Phase 4 — distribution

- Self-contained Apple Silicon DMG with a checksum-pinned flashing sidecar.
- Signed/notarized macOS DMG.
- Signed Windows installer and explicit Driver Doctor for WinUSB.
- Debian package with narrow udev rules and AppImage fallback.
Expand Down
31 changes: 24 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,37 @@ All notable changes to Touch Manager will be documented here. The project follow

## Unreleased

### Added

- On-demand, checksum-verified downloads for licensed official firmware.
- Content-addressed firmware cache in the application data directory.
- Curated community-directory and upstream-source links opened in the system browser.
- Official firmware redistribution notices.

### Planned

- Signed remote catalog updates.
- Maintained firmware builds with the TouchLink update protocol.
- Signed and notarized release automation.
- Windows and Linux hardware packaging.

## 0.3.0 - 2026-07-10

### Added

- Self-contained Apple Silicon application bundle with a built-in `dfu-util` 0.11
flashing engine and statically linked `libusb`.
- Startup flashing-engine health and version check shown on the Device page.
- Checksum-pinned third-party build automation, bundled GPL/LGPL notices, and corresponding
`dfu-util` and `libusb` source archives attached to releases.

### Changed

- Production firmware writes always use the bundled flashing engine. External paths remain
available only in development builds.

## 0.2.0 - 2026-07-10

### Added

- On-demand, checksum-verified downloads for licensed official firmware.
- Content-addressed firmware cache in the application data directory.
- Curated community-directory and upstream-source links opened in the system browser.
- Official firmware redistribution notices.

## 0.1.0 - 2026-07-10

### Added
Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ BOOT/RESET recovery path.
> connected during an installation and retain a known-good firmware binary. Automated
> tests never write to a connected device.

## What works in 0.2
## What works in 0.3

- Bundled metadata for 23 official and community Touch 2 instruments.
- On-demand downloading and verified local caching for redistributable official firmware.
Expand All @@ -21,7 +21,7 @@ BOOT/RESET recovery path.
- SHA-256, size, Thumb-vector, stack-pointer, and execution-layout validation.
- Fixed profiles for STM32 internal flash, Daisy `BOOT_SRAM`, and Daisy `BOOT_QSPI`.
- Detection of runtime USB, STM32 ROM DFU, Daisy Bootloader DFU, and serial ports.
- Profile-specific update instructions and an explicitly confirmed `dfu-util` installer.
- Profile-specific update instructions and a built-in, version-checked flashing engine.
- Runtime-return detection, recovery-aware results, and SQLite install history.
- USB serial diagnostics and support-transcript export.
- Responsive macOS-first interface built with Tauri, React, TypeScript, and Rust.
Expand All @@ -34,10 +34,11 @@ roadmap are in [BUILD_PLAN.md](BUILD_PLAN.md).
Download the latest macOS installer from
[GitHub Releases](https://github.com/alibros/touch-manager/releases).

The current preview is built for Apple Silicon Macs. It is ad-hoc signed rather than
Apple-notarized, so first launch may require Control-clicking the app, choosing **Open**,
or approving it in **System Settings → Privacy & Security**. Install `dfu-util` with
`brew install dfu-util` before writing firmware.
The current preview is built for Apple Silicon Macs and is fully self-contained: its
flashing engine is included in the application, so Homebrew and Terminal setup are not
required. It is ad-hoc signed rather than Apple-notarized, so first launch may require
Control-clicking the app, choosing **Open**, or approving it in **System Settings →
Privacy & Security**.

Release builds can download the eight official firmware binaries whose upstream MIT
licenses permit redistribution. Every download is checked against its catalog SHA-256 and
Expand Down Expand Up @@ -65,7 +66,7 @@ Prerequisites:
- macOS, Windows, or Linux with the [Tauri 2 prerequisites](https://v2.tauri.app/start/prerequisites/)
- Node.js 20.19 or newer
- Current stable Rust
- `dfu-util` 0.11 or newer for real hardware installation
- `dfu-util` 0.11 or newer for local development only; release builds include it

On macOS:

Expand Down Expand Up @@ -126,6 +127,12 @@ release still requires Apple Developer ID signing and notarization. Windows rele
explicit WinUSB guidance, and Linux releases need narrow udev rules; those distribution
tasks remain on the roadmap.

The tagged macOS release workflow builds `dfu-util` 0.11 and `libusb` 1.0.30 from their
checksum-pinned sources, statically links them, verifies that no non-system dynamic
libraries remain, and embeds the executable in the application bundle. Both corresponding
source archives and the required license notices ship with every release. See
[third-party notices](docs/THIRD_PARTY_NOTICES.md).

## Buttonless updates

The application contains the host-side TouchLink update request. Existing instruments do
Expand Down
36 changes: 36 additions & 0 deletions docs/THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Third-party notices

Touch Manager includes the following separately maintained open-source component in its
macOS release bundle.

## dfu-util 0.11

`dfu-util` is a host-side implementation of USB Device Firmware Upgrade protocols. Touch
Manager invokes it as a separate executable for firmware transfers.

- Project: <https://dfu-util.sourceforge.net/>
- Version: 0.11
- Source archive SHA-256: `b4b53ba21a82ef7e3d4c47df2952adf5fa494f499b6b0b57c58c5d04ae8ff19e`
- License: GNU General Public License, version 2 or later
- Copyright 2005–2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
- Copyright 2010–2021 Tormod Volden and Stefan Schmidt

The complete license text is bundled at `licenses/dfu-util-GPL-2.0.txt`. The exact
corresponding `dfu-util-0.11.tar.gz` source archive is attached to every Touch Manager
macOS release that includes this executable.

## libusb 1.0.30

The bundled `dfu-util` executable statically incorporates `libusb` for USB access.

- Project: <https://libusb.info/>
- Version: 1.0.30
- Source archive SHA-256: `fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf`
- License: GNU Lesser General Public License, version 2.1 or later

The complete license text is bundled at `licenses/libusb-LGPL-2.1.txt`. The exact
corresponding `libusb-1.0.30.tar.bz2` source archive is attached to every Touch Manager
macOS release that includes this library.

Touch Manager itself remains licensed under the MIT License. Third-party components remain
subject to their respective licenses.
Loading