Files
reterminal-dm4/chromium-setup/emmc-provisioning/docs/EMMC-PROVISIONING-GUIDE.md

8.1 KiB
Raw Blame History

Automatic eMMC provisioning for reTerminal DM4 (CM4)

This guide covers:

  1. Auto-flash: When the reTerminal is switched to boot mode (eMMC disable jumper) and connected via USB to a provisioning host, the host automatically deploys a golden image to the CM4 eMMC.
  2. Backup: When a device is detected (USB or network), the dashboard asks you to choose Backup or Deploy. Backup saves the device eMMC to a timestamped file in backups/.
  3. Network: If the device boots over the network and runs the provisioning client (see network-client/), it registers with the dashboard and appears as "Device (Network)"; you then choose Backup or Deploy. Deploy streams the golden image to the device; Backup uploads the device eMMC to the server.
  4. Cloud-init: The golden image includes cloud-init so each device configures itself on first boot (hostname, network, packages, kiosk setup).

Part 1: Auto-flash when reTerminal is in boot mode

How it works

  • reTerminal has an eMMC disable jumper (see reTerminal docs; often “J2” or “nRPIBOOT”). When the jumper is fitted, the CM4 boots in USB device mode and waits for rpiboot from the host.
  • You connect the reTerminals USB slave port to a provisioning PC (Linux).
  • udev detects the Raspberry Pi Foundation USB device (vendor 2b8e) and runs a trigger script.
  • The trigger starts a flash job that:
    1. Runs rpiboot (from the usbboot project). The CM4 then exposes its eMMC as a USB mass-storage device.
    2. After rpiboot exits, finds the new block device (eMMC) and writes your golden image to it with dd.
  • You remove the jumper and power cycle; the reTerminal boots from eMMC and runs cloud-init on first boot.

Provisioning host setup (Linux)

1. Build and install usbboot (rpiboot)

sudo apt-get install -y libusb-1.0-0-dev
git clone --depth=1 https://github.com/raspberrypi/usbboot
cd usbboot
make
sudo mkdir -p /opt/usbboot
sudo cp rpiboot /opt/usbboot/

2. Create golden image and config directory

  • Build your golden image (see Part 2) and place it where the script will find it, e.g.:

    sudo mkdir -p /var/lib/cm4-provisioning
    sudo cp /path/to/your/golden-reterminal.img /var/lib/cm4-provisioning/golden.img
    
  • Or use a different path and set GOLDEN_IMAGE when installing the script (see below).

3. Install the auto-flash script and trigger

# From this repo (chromium-setup/emmc-provisioning/host/)
cd chromium-setup/emmc-provisioning/host

sudo mkdir -p /opt/cm4-provisioning
sudo cp flash-emmc-on-connect.sh /opt/cm4-provisioning/
sudo chmod +x /opt/cm4-provisioning/flash-emmc-on-connect.sh

# Optional: override paths via environment (create env file)
echo 'GOLDEN_IMAGE=/var/lib/cm4-provisioning/golden.img' | sudo tee /opt/cm4-provisioning/env
echo 'RPIBOOT_DIR=/opt/usbboot' | sudo tee -a /opt/cm4-provisioning/env
echo 'EMMC_SIZE_BYTES=8589934592' | sudo tee -a /opt/cm4-provisioning/env   # 8GB; use 17179869184 for 16GB

sudo cp cm4-flash-trigger.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/cm4-flash-trigger.sh

If your golden image path or rpiboot path is different, set GOLDEN_IMAGE, RPIBOOT_DIR, and optionally EMMC_SIZE_BYTES in /opt/cm4-provisioning/env and source it from the script, or pass them into the systemd-run call in the trigger (e.g. by making the trigger source the env file and export variables before systemd-run).

4. Install udev rule

# From emmc-provisioning/host/
sudo cp 90-cm4-boot-mode.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

5. Enable provisioning (safety)

Provisioning runs only if the “enabled” file exists:

sudo mkdir -p /etc/cm4-provisioning
sudo touch /etc/cm4-provisioning/enabled

To disable auto-flash, remove that file: sudo rm /etc/cm4-provisioning/enabled.

6. Optional: pass environment into the flash job

If you use /opt/cm4-provisioning/env, update the trigger so the flash script sees those variables. For example change /usr/local/bin/cm4-flash-trigger.sh to:

#!/usr/bin/env bash
set -a
[[ -f /opt/cm4-provisioning/env ]] && source /opt/cm4-provisioning/env
set +a
export GOLDEN_IMAGE RPIBOOT_DIR EMMC_SIZE_BYTES
FLASH_SCRIPT="${CM4_FLASH_SCRIPT:-/opt/cm4-provisioning/flash-emmc-on-connect.sh}"
exec systemd-run --no-block --unit=cm4-flash-once --property=Environment="GOLDEN_IMAGE=$GOLDEN_IMAGE" ...

Or keep it simple and edit the defaults inside flash-emmc-on-connect.sh (e.g. GOLDEN_IMAGE, RPIBOOT_DIR, EMMC_SIZE_BYTES).

Usage

  1. Fit the eMMC disable jumper on the reTerminal.
  2. Connect the reTerminal USB slave port to the provisioning PC.
  3. Power the reTerminal (or apply power after USB).
  4. On the host, rpiboot will run automatically; when it exits, the script will dd the golden image to the eMMC. Watch logs: journalctl -u cm4-flash-once -f or journalctl -t cm4-flash -f.
  5. When done, remove the jumper and power cycle the reTerminal. It will boot from eMMC; cloud-init will run on first boot.

Part 2: Golden image with cloud-init

Raspberry Pi OS (recent versions) supports cloud-init using the NoCloud datasource: it reads user-data, meta-data, and optionally network-config from the boot (FAT32) partition.

Creating the golden image

  1. Flash Raspberry Pi OS (or your base image) to a spare SD card or a loop file.
  2. Mount the boot partition (first partition, FAT32). On the image file it might be at an offset; use losetup -P or mount the SDs partition.
  3. Add cloud-init NoCloud files on the boot partition (same level as config.txt, not in a subfolder for default NoCloud):
    • user-data main config (packages, runcmd, etc.)
    • meta-data optional (instance-id, local-hostname)
    • network-config optional (network config in netplan format)

You can use the examples in this repo:

# After mounting boot partition at e.g. /mnt/boot
# (On Raspberry Pi OS, boot is often /boot/firmware on the running system, or the first FAT partition of the image)
cp emmc-provisioning/cloud-init/user-data /mnt/boot/
cp emmc-provisioning/cloud-init/meta-data /mnt/boot/
cp emmc-provisioning/cloud-init/network-config /mnt/boot/
  1. Customise user-data and network-config (hostname, WiFi, packages, Chromium kiosk, etc.).
  2. Copy your kiosk/Chromium scripts into the image rootfs if needed (e.g. under /home/pi/ or /opt/) and reference them from user-data runcmd or a systemd unit.
  3. Unmount, then create a golden image from the SD or loop device (e.g. dd or dd of the whole block device). Use that as golden.img on the provisioning host.

Cloud-init file locations on the Pi

  • NoCloud: Boot partition root user-data, meta-data, network-config.
  • Some images expect them in a subfolder cloud-init/ or on a separate vfat partition labeled cidata; check your OS docs. Standard Raspberry Pi OS NoCloud uses the boot partition root.

Per-device config (optional)

NoCloud can also use a seed partition or config drive. For per-device hostname/settings you can:

  • Use meta-data instance-id and local-hostname and generate different meta-data per device when imaging (e.g. script that writes meta-data before flashing), or
  • Use a first-boot script that calls a provisioning server (e.g. by serial number) and applies device-specific config; cloud-init can launch that script from runcmd.

Summary

Step Action
1 Build usbboot, install rpiboot on provisioning host.
2 Create golden image with cloud-init user-data, meta-data, network-config on boot partition.
3 Install flash-emmc-on-connect.sh, cm4-flash-trigger.sh, and udev rule; set GOLDEN_IMAGE and enable file.
4 Put reTerminal in boot mode (jumper), connect USB to host; image is written automatically.
5 Remove jumper, power cycle; device boots from eMMC and cloud-init runs on first boot.

This gives you automatic deployment of the golden image to eMMC when the reTerminal is in boot mode, plus first-boot configuration via cloud-init.