diff --git a/emmc-provisioning/cloud-init/first-boot.md b/emmc-provisioning/cloud-init/first-boot.md index 4a7bd66..f776c11 100644 --- a/emmc-provisioning/cloud-init/first-boot.md +++ b/emmc-provisioning/cloud-init/first-boot.md @@ -9,7 +9,7 @@ This script runs once on first boot via cloud-init (see `user-data-remote-gnss.e 1. **Constants** — `FILE_SERVER`, `PI_USER`, paths, log file. 2. **Logging** — All output tee’d to `/var/log/first-boot.log`. 3. **Helpers** — `install_oneshot(name)` downloads `${name}.sh` from the file server and installs it as a one-shot autostart (runs once at pi’s first login, then deletes itself). -4. **Packages** — git, Chromium, wmctrl, SSH, swaybg, wlr-randr, maliit, xinput-calibrator, rpi-eeprom. +4. **Packages** — git, Chromium, wmctrl, SSH, swaybg, wlr-randr, maliit, xinput-calibrator. 5. **Kiosk files** — Download `start-chromium.sh` and `chromium-kiosk.desktop`; create autostart dir. 6. **Boot splash and wallpaper** — Download `splash.png`; install Plymouth custom theme; copy image for LightDM and desktop. 7. **LightDM** — Download `99-default-session.conf` (rpd-labwc) and `99-wallpaper.conf` to `/etc/lightdm/lightdm.conf.d/`. @@ -17,10 +17,8 @@ This script runs once on first boot via cloud-init (see `user-data-remote-gnss.e 9. **reTerminal DM drivers** — Seeed repo clone and `reTerminal.sh`. 10. **Re-apply splash** — Set `disable_splash=0`, Plymouth theme to `custom` only, `update-initramfs`. 11. **Dark theme** — Set GTK dark theme for user `pi`: `~/.config/gtk-3.0/settings.ini` with `gtk-application-prefer-dark-theme=1` and `gtk-theme-name=PiXnoir` (Raspberry Pi OS dark theme). -12. **CM4 EEPROM enable** — On CM4, `rpi-eeprom-update` is disabled by default. First-boot enables it by adding `RPI_EEPROM_USE_FLASHROM=1` and `CM4_ENABLE_RPI_EEPROM_UPDATE=1` to `/etc/default/rpi-eeprom-update`. **No config.txt changes are needed** — `dtoverlay=audremap`/`dtoverlay=spi-gpio40-45` are for the flashrom method only and **must not be added** as they conflict with the reTerminal DM display backlight (GPIO13 PWM). The bootloader method (`pieeprom.upd`) is used instead. -13. **Boot order** — If `rpi-eeprom-config` is available, set `BOOT_ORDER=0xf21` (eMMC first, then network, then restart). Also sets `NET_BOOT_MAX_RETRIES=3`, `DHCP_TIMEOUT=1500`, `DHCP_REQ_TIMEOUT=500`, `NET_INSTALL_AT_POWER_ON=0` so network boot fails fast when no TFTP server is available. On CM4 first boot this may be skipped (EEPROM not yet enabled); a one-shot systemd service runs after reboot to set boot order once. -14. **One-shots** — Download `set-rotation-once.sh` + `.desktop` from file server (wlr-randr for labwc). Wallpaper is set once via pcmanfm config during first-boot. -15. **Reboot.** +12. **One-shots** — Download `set-rotation-once.sh` + `.desktop` from file server (wlr-randr for labwc). Wallpaper is set once via pcmanfm config during first-boot. +13. **Reboot.** --- @@ -55,7 +53,6 @@ Installs the software needed for the rest of the script and for the kiosk: | **wlr-randr** | Display rotation for wlroots/labwc; one-shot sets “Left” (transform 270). | | **maliit-keyboard** | On-screen keyboard for touch input. | | **xinput-calibrator** | Touchscreen calibration (optional; run manually if needed). | -| **rpi-eeprom** | EEPROM tools (`rpi-eeprom-update`, `rpi-eeprom-config`) for Pi 4/CM4 boot order (e.g. network first). | --- @@ -133,13 +130,7 @@ The reTerminal DM default is portrait. Rotation is set **persistently** via the First-boot sets a dark GTK theme for user **pi** via **`~/.config/gtk-3.0/settings.ini`** with **`gtk-application-prefer-dark-theme=1`** and **`gtk-theme-name=PiXnoir`**. On older images use **Adwaita-dark** if PiXnoir is missing. -## CM4: enable rpi-eeprom-update (for boot order) -On **CM4**, first-boot enables `rpi-eeprom-update` by setting **`RPI_EEPROM_USE_FLASHROM=1`** and **`CM4_ENABLE_RPI_EEPROM_UPDATE=1`** in **`/etc/default/rpi-eeprom-update`**. **No dtparams are added to config.txt.** `dtoverlay=audremap` and `dtoverlay=spi-gpio40-45` are only needed for the *flashrom* (direct SPI) update method — they **must not** be added because `audremap` remaps audio to GPIO12/13, which conflicts with the reTerminal DM display backlight PWM on GPIO13, causing a blank screen. The bootloader file method (`pieeprom.upd`) works without these overlays. See: [usbboot](https://github.com/raspberrypi/usbboot/blob/master/Readme.md). - -## Boot order (eMMC first, then network) - -If **`rpi-eeprom-config`** and **`rpi-eeprom-update`** are present (Pi 4/CM4), the script sets the EEPROM **`BOOT_ORDER=0xf21`**: try **SD/eMMC** first (0x1), then **network** (0x2), then **restart** (0xf). Network boot settings are tuned for fast fallback: `NET_BOOT_MAX_RETRIES=3`, `DHCP_TIMEOUT=1500` (1.5s), `DHCP_REQ_TIMEOUT=500` (0.5s), `NET_INSTALL_AT_POWER_ON=0`. The device boots from eMMC normally; if eMMC is blank it tries network boot for re-provisioning but gives up quickly when no TFTP server is available. **Pi 4:** applied on first-boot; EEPROM update scheduled for next reboot. **CM4:** a one-shot service (**`set-cm4-boot-order-once.service`**) runs after the next boot and sets the boot order, then removes itself. If “Could not read current EEPROM config” appears, run `sudo rpi-eeprom-update -l` on the device to see if a firmware file is listed; you can set boot order manually with `rpi-eeprom-config` if needed. If the tools are not available, the step is skipped. ## Reboot diff --git a/emmc-provisioning/cloud-init/first-boot.sh b/emmc-provisioning/cloud-init/first-boot.sh index 29b1f03..cba3d79 100644 --- a/emmc-provisioning/cloud-init/first-boot.sh +++ b/emmc-provisioning/cloud-init/first-boot.sh @@ -57,9 +57,9 @@ install_oneshot() { log "--- Installing packages ---" log "Running apt-get update ..." apt-get update -qq -log "Installing: git chromium wmctrl openssh-server swaybg wlr-randr maliit-keyboard xinput-calibrator rpi-eeprom" +log "Installing: git chromium wmctrl openssh-server swaybg wlr-randr maliit-keyboard xinput-calibrator" apt-get install -y -qq git chromium wmctrl openssh-server \ - swaybg wlr-randr maliit-keyboard xinput-calibrator rpi-eeprom + swaybg wlr-randr maliit-keyboard xinput-calibrator log "Packages installed successfully" # --- 2. Dirs and kiosk files from file server --- @@ -197,101 +197,6 @@ if [[ -f "$CMDLINE_PATH" ]]; then fi fi -# --- 6c. CM4: enable rpi-eeprom-update so boot order can be set --- -# On CM4, rpi-eeprom-update is disabled by default. Enable it by setting flags in /etc/default/rpi-eeprom-update. -# We use the bootloader method (pieeprom.upd file placed in /boot/firmware), NOT flashrom. -# NOTE: Do NOT add dtoverlay=audremap or dtoverlay=spi-gpio40-45 to config.txt. -# Those are only needed for the flashrom (direct SPI) method, and audremap CONFLICTS with -# the reTerminal DM display backlight (both use GPIO13 PWM). -# See: https://github.com/raspberrypi/usbboot , /etc/default/rpi-eeprom-update -log "--- CM4 EEPROM update enable (for boot order) ---" -EEPROM_DEFAULT="/etc/default/rpi-eeprom-update" -if [[ ! -f "$EEPROM_DEFAULT" ]]; then - touch "$EEPROM_DEFAULT" - log "Created $EEPROM_DEFAULT" -fi -grep -q '^RPI_EEPROM_USE_FLASHROM=' "$EEPROM_DEFAULT" && sed -i 's/^RPI_EEPROM_USE_FLASHROM=.*/RPI_EEPROM_USE_FLASHROM=1/' "$EEPROM_DEFAULT" || echo 'RPI_EEPROM_USE_FLASHROM=1' >> "$EEPROM_DEFAULT" -grep -q '^CM4_ENABLE_RPI_EEPROM_UPDATE=' "$EEPROM_DEFAULT" && sed -i 's/^CM4_ENABLE_RPI_EEPROM_UPDATE=.*/CM4_ENABLE_RPI_EEPROM_UPDATE=1/' "$EEPROM_DEFAULT" || echo 'CM4_ENABLE_RPI_EEPROM_UPDATE=1' >> "$EEPROM_DEFAULT" -log "Set RPI_EEPROM_USE_FLASHROM=1 and CM4_ENABLE_RPI_EEPROM_UPDATE=1 in $EEPROM_DEFAULT" - -# --- 6d. Boot order: eMMC/SD first, then network, then restart (0xf21) --- -# BOOT_ORDER nibbles (right-to-left): 1=SD/eMMC, 2=network (TFTP), f=restart loop. -# On CM4, rpi-eeprom-update -l only works after reboot (once 6c is applied). So we try now; if it fails, a one-shot runs after next boot. -log "--- Boot order (0xf21: eMMC/SD first, then network, restart) ---" -BOOTCONF="/tmp/first-boot-eeprom-conf.txt" -BOOT_ORDER_SET=0 -if command -v rpi-eeprom-config >/dev/null 2>&1 && command -v rpi-eeprom-update >/dev/null 2>&1; then - if PEE="$(rpi-eeprom-update -l 2>/dev/null)" && [[ -n "$PEE" ]] && [[ -f "$PEE" ]]; then - rpi-eeprom-config "$PEE" > "$BOOTCONF" 2>/dev/null || true - fi - if [[ -s "$BOOTCONF" ]]; then - sed -i 's/^BOOT_ORDER=.*/BOOT_ORDER=0xf21/' "$BOOTCONF" - grep -q '^BOOT_ORDER=' "$BOOTCONF" || echo 'BOOT_ORDER=0xf21' >> "$BOOTCONF" - # Limit network boot: 3 retries, 1500ms DHCP timeout (fail fast to eMMC) - sed -i '/^NET_BOOT_MAX_RETRIES=/d; /^DHCP_TIMEOUT=/d; /^DHCP_REQ_TIMEOUT=/d; /^TFTP_IP=/d; /^NET_INSTALL_AT_POWER_ON=/d' "$BOOTCONF" - echo 'NET_BOOT_MAX_RETRIES=3' >> "$BOOTCONF" - echo 'DHCP_TIMEOUT=1500' >> "$BOOTCONF" - echo 'DHCP_REQ_TIMEOUT=500' >> "$BOOTCONF" - echo 'NET_INSTALL_AT_POWER_ON=0' >> "$BOOTCONF" - if rpi-eeprom-config --apply "$BOOTCONF" 2>/dev/null; then - log "Boot order set to 0xf21 (eMMC first, then network, restart); EEPROM update scheduled for next reboot" -@ BOOT_ORDER_SET=1 - else - log "WARNING: rpi-eeprom-config --apply failed; boot order unchanged" - fi - else - log "rpi-eeprom-update -l did not return a config (on CM4 this is normal until after reboot with 6c applied); scheduling one-shot to set boot order after next boot" - fi - rm -f "$BOOTCONF" -else - log "rpi-eeprom-config/rpi-eeprom-update not found; skipping boot order (not a Pi4/CM4 or package missing)" -fi - -# If boot order was not set (e.g. CM4 first boot), install a one-shot systemd service to set it after reboot -if [[ "$BOOT_ORDER_SET" -eq 0 ]] && command -v rpi-eeprom-config >/dev/null 2>&1 && command -v rpi-eeprom-update >/dev/null 2>&1; then - ONCE_SCRIPT="/usr/local/bin/set-cm4-boot-order-once.sh" - ONCE_SVC="/etc/systemd/system/set-cm4-boot-order-once.service" - cat > "$ONCE_SCRIPT" << 'SETBOOTEOF' -#!/bin/bash -# One-shot: set BOOT_ORDER=0xf21 (eMMC first, then network) when rpi-eeprom-update becomes available (e.g. after CM4 enable and reboot). -BOOTCONF="/tmp/eeprom-boot-order-once.txt" -if PEE="$(rpi-eeprom-update -l 2>/dev/null)" && [[ -n "$PEE" ]] && [[ -f "$PEE" ]]; then - rpi-eeprom-config "$PEE" > "$BOOTCONF" 2>/dev/null - if [[ -s "$BOOTCONF" ]]; then - sed -i 's/^BOOT_ORDER=.*/BOOT_ORDER=0xf21/' "$BOOTCONF" - grep -q '^BOOT_ORDER=' "$BOOTCONF" || echo 'BOOT_ORDER=0xf21' >> "$BOOTCONF" - sed -i '/^NET_BOOT_MAX_RETRIES=/d; /^DHCP_TIMEOUT=/d; /^DHCP_REQ_TIMEOUT=/d; /^TFTP_IP=/d; /^NET_INSTALL_AT_POWER_ON=/d' "$BOOTCONF" - echo 'NET_BOOT_MAX_RETRIES=3' >> "$BOOTCONF" - echo 'DHCP_TIMEOUT=1500' >> "$BOOTCONF" - echo 'DHCP_REQ_TIMEOUT=500' >> "$BOOTCONF" - echo 'NET_INSTALL_AT_POWER_ON=0' >> "$BOOTCONF" - if rpi-eeprom-config --apply "$BOOTCONF" 2>/dev/null; then - echo "Boot order set to 0xf21 (eMMC first, then network)" - fi - fi - rm -f "$BOOTCONF" -fi -systemctl disable set-cm4-boot-order-once.service 2>/dev/null || true -rm -f /etc/systemd/system/set-cm4-boot-order-once.service -rm -f "$0" -SETBOOTEOF - chmod 755 "$ONCE_SCRIPT" - cat > "$ONCE_SVC" << 'SVCEOF' -[Unit] -Description=Set CM4 boot order once (eMMC first, then network) -After=multi-user.target - -[Service] -Type=oneshot -ExecStart=/usr/local/bin/set-cm4-boot-order-once.sh -RemainAfterExit=no - -[Install] -WantedBy=multi-user.target -SVCEOF - systemctl enable set-cm4-boot-order-once.service 2>/dev/null && log "Enabled set-cm4-boot-order-once.service to set boot order after next boot" -fi - # --- 7. One-shots (wallpaper already set in pcmanfm config above; rotation is via cmdline.txt) --- log "--- One-shot scripts (if any) ---" # Rotation is set persistently in cmdline.txt (video=DSI-1:rotate=90), not via one-shot script. diff --git a/emmc-provisioning/docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md b/emmc-provisioning/docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md index d43a2a8..3fe9160 100644 --- a/emmc-provisioning/docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md +++ b/emmc-provisioning/docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md @@ -6,7 +6,7 @@ This describes the full flow from power-on to eMMC deploy/backup when using **ne ## Overview -1. **reTerminal** is set to try **eMMC first, then network** (EEPROM `BOOT_ORDER=0xf21`). +1. **reTerminal** is set to try **eMMC first, then network** (EEPROM `BOOT_ORDER=0xf21`) via the dashboard **Update EEPROM** when the device is connected over USB boot, or set manually. 2. It is connected to the **same LAN as the LXC’s eth1** (e.g. 10.20.50.0/24). 3. On power-on it gets an IP via **DHCP** and loads **boot files via TFTP** from the LXC. 4. The **netboot environment** (kernel + rootfs) runs **provisioning-client.sh**, which registers with the **dashboard** and polls for an action. @@ -29,7 +29,7 @@ The **dashboard** (Flask) runs in the LXC and is reachable at e.g. `http://10.20 ### 2. reTerminal (device) -- **EEPROM**: `BOOT_ORDER=0xf21` (eMMC first, then network). Can be set by cloud-init first-boot on an already-flashed device. +- **EEPROM**: `BOOT_ORDER=0xf21` (eMMC first, then network). Set via dashboard **Update EEPROM** (USB boot) or manually (usbboot recovery / `rpi-eeprom-config` on device). Not set by first-boot. - **Network**: Ethernet connected to the same segment as the LXC’s **eth1** (e.g. same switch/VLAN as 10.20.50.0/24). - On **power-on**: 1. Pi 4/CM4 firmware does **DHCP** on the wired interface. diff --git a/emmc-provisioning/docs/NETWORK-BOOT-LXC.md b/emmc-provisioning/docs/NETWORK-BOOT-LXC.md index 6280b8e..4e33f20 100644 --- a/emmc-provisioning/docs/NETWORK-BOOT-LXC.md +++ b/emmc-provisioning/docs/NETWORK-BOOT-LXC.md @@ -67,7 +67,7 @@ Your current LXC already has eth0 (10.130.60.141) and eth1 (10.20.50.1); the set ## After setup: reTerminal network boot -1. Set the reTerminal **boot order** to try eMMC first, then network (e.g. `BOOT_ORDER=0xf21`; see cloud-init/first-boot). +1. Set the reTerminal **boot order** to try eMMC first, then network (e.g. `BOOT_ORDER=0xf21`): use the dashboard **Update EEPROM** when the device is connected via USB boot, or set manually (usbboot recovery / `rpi-eeprom-config` on device). Not set by first-boot. 2. Connect the reTerminal to the **same network as the LXC’s eth1** (e.g. 10.20.50.0/24). 3. Power on; it will get an IP via DHCP and load boot files via TFTP from the LXC. 4. For **provisioning** (Backup/Deploy), the netboot environment must run **network-client/provisioning-client.sh** with `PROVISIONING_SERVER=http://10.20.50.1:5000` so it talks to the dashboard on the LXC. diff --git a/emmc-provisioning/scripts/install-eeprom-tools-on-lxc.sh b/emmc-provisioning/scripts/install-eeprom-tools-on-lxc.sh old mode 100755 new mode 100644 index eb339d4..0b1c40e --- a/emmc-provisioning/scripts/install-eeprom-tools-on-lxc.sh +++ b/emmc-provisioning/scripts/install-eeprom-tools-on-lxc.sh @@ -27,25 +27,19 @@ else fi mkdir -p "$EEPROM_DIR" -cd "$EEPROM_DIR" - echo "Downloading rpi-eeprom-config..." $GET_O "$EEPROM_DIR/rpi-eeprom-config" "$RPI_EEPROM_RAW/rpi-eeprom-config" $GET_O "$EEPROM_DIR/rpi-eeprom-digest" "$RPI_EEPROM_RAW/rpi-eeprom-digest" chmod +x "$EEPROM_DIR/rpi-eeprom-config" "$EEPROM_DIR/rpi-eeprom-digest" -echo "Finding latest BCM2711 EEPROM firmware..." LATEST_FW=$($GET "https://api.github.com/repos/raspberrypi/rpi-eeprom/contents/firmware-2711/default" \ | grep -o '"name" *: *"pieeprom-[^"]*\.bin"' | sed 's/"name" *: *"//;s/"//' | sort | tail -1) - if [ -z "$LATEST_FW" ]; then echo "WARNING: Could not determine latest firmware from GitHub API. Try again or download pieeprom.bin manually." - exit 1 +else + $GET_O "$EEPROM_DIR/pieeprom.bin" "$RPI_EEPROM_RAW/firmware-2711/default/$LATEST_FW" fi -echo "Downloading $LATEST_FW..." -$GET_O "$EEPROM_DIR/pieeprom.bin" "$RPI_EEPROM_RAW/firmware-2711/default/$LATEST_FW" - if [ ! -s "$EEPROM_DIR/pieeprom.bin" ]; then echo "ERROR: pieeprom.bin is missing or empty" exit 1 @@ -56,5 +50,4 @@ if ! python3 "$EEPROM_DIR/rpi-eeprom-config" "$EEPROM_DIR/pieeprom.bin" >/dev/nu echo "WARNING: rpi-eeprom-config could not read pieeprom.bin (non-fatal)" fi -echo "Done. EEPROM tools installed:" -ls -la "$EEPROM_DIR" +echo "Done. EEPROM tools installed to $EEPROM_DIR"