initial commit

This commit is contained in:
2025-04-17 13:21:38 +02:00
commit 24c45efa75
30 changed files with 1645 additions and 0 deletions

4
Config.in Normal file
View File

@@ -0,0 +1,4 @@
# Config.in for Auracaster System BR2_EXTERNAL tree
# Include custom packages
source "$BR2_EXTERNAL_AURACASTER_SYSTEM_PATH/package/swupdate-scripts/Config.in"

134
README.md Normal file
View File

@@ -0,0 +1,134 @@
# Auracaster System - Buildroot with SWUpdate A/B System
This project implements a Buildroot-based system for Raspberry Pi 3 with SWUpdate A/B partitioning for robust over-the-air updates.
## Overview
The Auracaster System provides a complete solution for creating a robust embedded Linux system with A/B partition updates using the SWUpdate framework. This allows for safe, reliable updates with automatic rollback capability if an update fails.
### Key Features
- **A/B Partition System**: Two rootfs partitions (A and B) for failsafe updates
- **SWUpdate Integration**: Web interface for uploading and applying updates
- **Automatic Fallback**: If an update fails to boot, the system reverts to the previous partition
- **Raspberry Pi 3 Support**: Optimized for Raspberry Pi 3 hardware
- **BR2_EXTERNAL Structure**: Follows Buildroot's recommended external tree pattern
## Directory Structure
```
auracaster-system/
├── Config.in # Main config file for BR2_EXTERNAL
├── external.desc # BR2_EXTERNAL description file
├── configs/ # Custom defconfigs
│ └── raspberrypi3_swupdate_defconfig
├── board/ # Board-specific files
│ └── raspberrypi3_swupdate/ # Configuration for RPi3 with SWUpdate
├── package/ # Custom packages
│ └── swupdate-scripts/ # Custom scripts for SWUpdate
├── example/ # Example update package
│ └── create-update-package.sh # Script to create a sample update
└── flash_sdcard.sh # Script to flash SD card
```
## Building the System
### Prerequisites
- Buildroot checkout (in `../buildroot` relative to this repository)
- Build dependencies for Buildroot (see Buildroot documentation)
- At least 10GB of free disk space
- Root/sudo access (for SD card flashing)
### Build Steps
1. Configure Buildroot to use this external tree:
```bash
cd ../buildroot
make BR2_EXTERNAL=../auracaster-system raspberrypi3_swupdate_defconfig
```
2. Build the system:
```bash
make
```
The build process will take some time (30-60 minutes depending on your system). Once complete, the output images will be in `../buildroot/output/images/`.
## Flashing to SD Card
Use the provided script to flash the image to your SD card:
```bash
sudo ./flash_sdcard.sh
```
Follow the on-screen prompts to select the correct device and confirm the flashing operation.
## Partition Layout
The system uses the following partition layout on the SD card:
1. **Boot Partition (64MB)**: Contains bootloader, kernel, and boot configuration
2. **RootFS A (512MB)**: First root filesystem partition
3. **RootFS B (512MB)**: Second root filesystem partition
4. **Data Partition (Remaining Space)**: For persistent data storage
## Update Process
### Creating an Update Package
Use the provided example script to create an update package:
```bash
cd example
./create-update-package.sh
```
This creates an `auracaster-update.swu` file that can be applied through the web interface.
### Applying an Update via Web Interface
1. Boot the Raspberry Pi with the flashed SD card
2. Connect to the same network as the Raspberry Pi
3. Access the web interface at `http://<raspberry-pi-ip>:8080`
4. Upload the `.swu` file through the web interface
5. Once the update is complete, reboot the device
6. The system will boot from the updated partition
### Update Verification
The system will track boot attempts. If the updated system fails to boot properly (as determined by the boot counter mechanism), it will automatically fall back to the previous working partition.
## U-Boot Environment
The U-Boot environment manages the A/B boot selection. Key variables include:
- `active_part`: Current active partition (A or B)
- `inactive_part`: Partition that will receive updates
- `bootcount`: Number of boot attempts for the current partition
- `bootlimit`: Maximum allowed boot attempts before fallback
## Troubleshooting
### System Won't Boot
If the system fails to boot completely:
1. Connect a monitor to the Raspberry Pi to view boot messages
2. If the system is falling back to the previous partition, check the logs for errors
3. You can manually force a boot from a specific partition by editing the U-Boot environment
### Update Fails
If an update fails to apply:
1. Check network connectivity
2. Verify the SWUpdate web server is running (port 8080)
3. Examine the update package format and contents
## License
This project is distributed under the terms of the GPL v2 license.

108
USAGE_GUIDE.md Normal file
View File

@@ -0,0 +1,108 @@
# Auracaster System - Quick Start Guide
This guide walks you through building the Auracaster system, flashing it to an SD card, and performing an A/B update.
## Building the System
1. Clone or navigate to your Buildroot repository:
```bash
cd ../buildroot
```
2. Configure Buildroot to use our external tree:
```bash
make BR2_EXTERNAL=../auracaster-system raspberrypi3_swupdate_defconfig
```
3. Build the system (this will take some time):
```bash
make
```
## Flashing to SD Card
1. Insert your SD card into your computer
2. Run the flashing script with sudo:
```bash
cd ../auracaster-system
sudo ./flash_sdcard.sh
```
3. Follow the prompts to select your SD card device
## Initial Boot
1. Insert the SD card into your Raspberry Pi 3
2. Connect Ethernet and power
3. Wait for the system to boot (1-2 minutes)
4. Discover the IP address (check your router or use `nmap -sP 192.168.1.0/24`)
5. The system will be initially running from partition A
## Creating an Update Package
1. Create a simple update package:
```bash
cd example
./create-update-package.sh
```
2. This creates `auracaster-update.swu` which would update the inactive partition (B)
## Applying the Update
1. Access the SWUpdate web interface in your browser:
```
http://<raspberry-pi-ip>:8080
```
2. You should see the Auracaster System Update interface
3. Select "Choose File" and pick the `auracaster-update.swu` file
4. Click "Upload" to start the update process
5. The progress bar will show the update status
6. Once complete, you'll see "Update successful"
## Verifying the Update
1. Reboot the system (either through the web interface or SSH)
2. After reboot, the system will now be running from partition B
3. You can verify this by checking the system status:
```bash
swupdate-ab-helper --status
```
## Testing Automatic Fallback
If you want to test the automatic fallback mechanism:
1. SSH into the system
2. Make the active partition unbootable (for testing purposes only):
```bash
# Corrupt kernel on the currently active partition
swupdate-ab-helper --toggle
reboot
```
3. The system will attempt to boot from the now-corrupt partition
4. After 3 failed attempts, it will automatically fall back to the previous partition
## Tips and Troubleshooting
- **Network Issues**: If you can't access the web interface, check your network connection and firewall settings
- **Update Failures**: Check for errors in the swupdate logs: `journalctl -u swupdate`
- **Manual Partition Toggle**: You can manually switch between partitions: `swupdate-ab-helper --toggle && reboot`
- **Checking Update Status**: Run `swupdate-check status` to see current system status
## Next Steps
- Create your own custom update packages
- Modify the web interface to include your branding
- Implement secure updates with cryptographic signatures

View File

@@ -0,0 +1,56 @@
# U-Boot boot script for Raspberry Pi 3 with A/B boot
# This script will be converted to boot.scr by the post-image.sh script
echo "DEBUG: Starting boot process..."
echo "DEBUG: U-Boot version: ${ver}"
echo "DEBUG: Board: ${board_name}"
# Set load addresses
setenv kernel_addr_r 0x01000000
setenv fdt_addr_r 0x02000000
echo "DEBUG: Load addresses set - kernel: ${kernel_addr_r}, fdt: ${fdt_addr_r}"
# Print current environment variables
echo "DEBUG: Current boot variables:"
echo "DEBUG: active_part=${active_part}"
echo "DEBUG: active_root=${active_root}"
echo "DEBUG: bootcount=${bootcount}"
echo "DEBUG: bootlimit=${bootlimit}"
# Read and increment boot count
echo "DEBUG: Checking bootcount..."
if test ${bootcount} -lt ${bootlimit}; then
echo "DEBUG: Incrementing bootcount from ${bootcount} to $((${bootcount} + 1))"
setexpr bootcount ${bootcount} + 1
echo "DEBUG: Saving environment..."
saveenv
echo "DEBUG: Environment saved"
fi
# If bootcount has reached bootlimit, switch to alternate boot
echo "DEBUG: Checking if bootcount >= bootlimit..."
if test ${bootcount} -ge ${bootlimit}; then
echo "Boot failed too many times. Switching to alternate partition."
echo "DEBUG: Running altbootcmd..."
run altbootcmd
echo "DEBUG: Resetting bootcount to 0"
setenv bootcount 0
echo "DEBUG: Saving environment..."
saveenv
echo "DEBUG: Environment saved"
fi
# List files in boot partition
echo "DEBUG: Listing files in boot partition:"
ls mmc 0:1
# Boot the system
echo "DEBUG: Preparing to boot from partition ${active_part}..."
echo "DEBUG: Will execute: bootcmd_${active_part}"
echo "DEBUG: bootcmd_${active_part}=${bootcmd_${active_part}}"
echo "DEBUG: Booting from partition ${active_part}..."
run bootcmd_${active_part}
# If we reach here, booting failed. Try alternate boot.
echo "DEBUG: Primary boot failed. Trying alternate partition..."
run altbootcmd

View File

@@ -0,0 +1 @@
console=ttyS0,115200 rootwait

View File

@@ -0,0 +1,20 @@
# Enable 64-bit mode
arm_64bit=1
# configure the uart
enable_uart=1
core_freq=250
init_uart_clock=48000000
init_uart_baud=115200
uart_2ndstage=1
# Disable HDMI to reduce noise
hdmi_ignore_hotplug=1
hdmi_blanking=2
disable_splash=1
# gpu mem config (seems to be totally nececcarry - smaller than 32m does not boot on rpi3)
gpu_mem=32
# start the bootloader which then selects system A or B
kernel=u-boot.bin

View File

@@ -0,0 +1,23 @@
# Raspberry Pi 3 configuration for UART debugging
# Enable 64-bit mode
arm_64bit=1
# UART configuration - Comprehensive settings
enable_uart=1
core_freq=250
init_uart_clock=48000000
init_uart_baud=115200
uart_2ndstage=1
#dtparam=uart0=on
# Disable HDMI to reduce noise
hdmi_ignore_hotplug=1
hdmi_blanking=2
disable_splash=1
# Use zImage as the kernel
kernel=zImage
# For better performance (seems to be totally nececcarry)
gpu_mem=128

View File

@@ -0,0 +1,78 @@
image boot.vfat {
vfat {
files = {
"bcm2710-rpi-3-b.dtb",
"bcm2710-rpi-3-b-plus.dtb",
"bcm2710-rpi-cm3.dtb",
"cmdline.txt",
"config.txt",
"boot.scr",
"uboot-env.img",
"zImage"
}
file overlays/README {
image = "rpi-firmware/overlays/README"
}
file bootcode.bin {
image = "rpi-firmware/bootcode.bin"
}
file fixup.dat {
image = "rpi-firmware/fixup.dat"
}
file start.elf {
image = "rpi-firmware/start.elf"
}
}
size = 32M
}
image rootfs-A.ext4 {
ext4 {
label = "rootfs-A"
use-mke2fs = true
}
size = 256M
}
image rootfs-B.ext4 {
ext4 {
label = "rootfs-B"
use-mke2fs = true
}
size = 256M
}
image data.ext4 {
ext4 {
label = "data"
use-mke2fs = true
}
size = 128M
}
image sdcard.img {
hdimage {
partition-table-type = "mbr"
}
partition boot {
partition-type = 0xC
bootable = "true"
image = "boot.vfat"
}
partition rootfs-A {
partition-type = 0x83
image = "rootfs-A.ext4"
}
partition rootfs-B {
partition-type = 0x83
image = "rootfs-B.ext4"
}
partition data {
partition-type = 0x83
image = "data.ext4"
}
}

View File

@@ -0,0 +1,42 @@
#!/bin/bash
set -e
BOARD_DIR="$(dirname $0)"
BOARD_NAME="$(basename ${BOARD_DIR})"
GENIMAGE_CFG="${BOARD_DIR}/genimage-${BOARD_NAME}.cfg"
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
# Add a console on tty1
if [ -e ${TARGET_DIR}/etc/inittab ]; then
grep -qE '^tty1::' ${TARGET_DIR}/etc/inittab || \
sed -i '/GENERIC_SERIAL/a\
tty1::respawn:/sbin/getty -L tty1 0 vt100 # HDMI console' ${TARGET_DIR}/etc/inittab
fi
# Create swupdate directory structure
mkdir -p ${TARGET_DIR}/etc/swupdate
mkdir -p ${TARGET_DIR}/var/www/swupdate
mkdir -p ${TARGET_DIR}/var/lib/swupdate
mkdir -p ${TARGET_DIR}/etc/swupdate/conf.d
# Copy swupdate configuration
install -m 0644 ${BOARD_DIR}/swupdate.cfg ${TARGET_DIR}/etc/swupdate/swupdate.cfg
# Set up fstab for A/B partitioning
cat > ${TARGET_DIR}/etc/fstab << EOF
# <file system> <mount pt> <type> <options> <dump> <pass>
/dev/mmcblk0p1 /boot vfat defaults 0 0
/dev/root / ext4 rw,noauto 0 1
/dev/mmcblk0p4 /data ext4 defaults 0 0
proc /proc proc defaults 0 0
devpts /dev/pts devpts defaults,gid=5,mode=620,ptmxmode=0666 0 0
tmpfs /dev/shm tmpfs mode=0777 0 0
tmpfs /tmp tmpfs mode=1777 0 0
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
sysfs /sys sysfs defaults 0 0
EOF
# Create systemd services for swupdate
mkdir -p ${TARGET_DIR}/etc/systemd/system/
install -m 0644 ${BOARD_DIR}/swupdate.service ${TARGET_DIR}/etc/systemd/system/

View File

@@ -0,0 +1,63 @@
#!/bin/bash
set -e
BOARD_DIR="$(dirname $0)"
BOARD_NAME="$(basename ${BOARD_DIR})"
GENIMAGE_CFG="${BOARD_DIR}/genimage-${BOARD_NAME}.cfg"
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
# Copy u-boot.bin to the firmware directory for Raspberry Pi bootloader
echo "Copying u-boot.bin to rpi-firmware directory..."
if [ -f "${BINARIES_DIR}/u-boot.bin" ]; then
cp "${BINARIES_DIR}/u-boot.bin" "${BINARIES_DIR}/rpi-firmware/"
else
echo "WARNING: u-boot.bin not found in ${BINARIES_DIR}" >&2
fi
# Pass arguments to genimage
GENIMAGE_ARGS="--rootpath ${TARGET_DIR}"
# Create the boot.scr U-Boot script
${HOST_DIR}/bin/mkimage -A arm -O linux -T script -C none -d ${BOARD_DIR}/boot.scr.txt ${BINARIES_DIR}/boot.scr
# Create a file to indicate that this is rootfs A
touch ${TARGET_DIR}/etc/rootfs-A
# Create an empty ext4 rootfs-B image of the same size as rootfs
cp ${BINARIES_DIR}/rootfs.ext4 ${BINARIES_DIR}/rootfs-B.ext4
# Create uboot environment
${HOST_DIR}/bin/mkenvimage -s 131072 -o "${BINARIES_DIR}/uboot-env.img" "${BOARD_DIR}/uboot-env.txt"
# Copy U-Boot environment image as uboot.env to rpi-firmware directory
cp "${BINARIES_DIR}/uboot-env.img" "${BINARIES_DIR}/rpi-firmware/uboot.env"
# Create version file
echo "VERSION=${BR2_VERSION_FULL}" > ${BINARIES_DIR}/version
# Mark inactive rootfs partition as clean
touch ${BINARIES_DIR}/.rootfs-B.ext4.done
# Copy the cmdline.txt and config.txt files
cp ${BOARD_DIR}/cmdline.txt ${BINARIES_DIR}/cmdline.txt
cp ${BOARD_DIR}/config.txt ${BINARIES_DIR}/config.txt
rm -rf "${GENIMAGE_TMP}"
genimage \
--loglevel 1 \
${GENIMAGE_ARGS} \
--tmppath "${GENIMAGE_TMP}" \
--inputpath "${BINARIES_DIR}" \
--outputpath "${BINARIES_DIR}" \
--config "${GENIMAGE_CFG}"
# Create symlink for easy flashing with dd
ln -sf "${BINARIES_DIR}/sdcard.img" "${BINARIES_DIR}/auracaster-swupdate.img"
# Create a compressed version for distribution
if [ -x "$(command -v xz)" ]; then
xz -T0 -c "${BINARIES_DIR}/sdcard.img" > "${BINARIES_DIR}/auracaster-swupdate.img.xz"
fi
exit $?

View File

@@ -0,0 +1 @@
1.0.0

View File

@@ -0,0 +1,36 @@
# SWUpdate runtime configuration
globals = {
verbose = true;
loglevel = 5;
syslog = true;
# Create a file to notify scripts that update is complete
postupdatecmd = "touch /tmp/swupdate.done";
};
# Partition handler for raw partitions
raw-handler = {
# Example: Specify which partitions can be updated
partitions = ( { name = "rootfs-B"; device = "/dev/mmcblk0p3"; } );
};
# For bootloader environment
bootloader = {
# U-Boot environment
environment = {
device = "/dev/mmcblk0p1";
file = "uboot-env.img";
};
# What to set after successful update
set-variables = (
{name = "bootcount"; value = "0";},
{name = "upgrade_available"; value = "1";},
{name = "active_part"; value = "${inactive_part}";},
{name = "active_root"; value = "${inactive_root}";},
{name = "inactive_part"; value = "${active_part}";},
{name = "inactive_root"; value = "${active_root}";}
);
};
# Include additional configuration files
include = "conf.d/*.cfg";

View File

@@ -0,0 +1,41 @@
/* SWUpdate configuration file */
globals :
{
verbose = true;
loglevel = 5;
syslog = true;
/* Create a file on startup for the web interface */
postupdatecmd = "touch /tmp/swupdate.done";
};
webserver :
{
document_root = "/var/www/swupdate";
port = 8080;
};
download :
{
retries = 3;
timeout = 1800;
};
identify :
{
/* This identifies the device for update targeting */
board = "raspberrypi3";
hw-revision = "1.0";
software-set = "stable";
};
suricatta :
{
/* Configure for push notifications - not enabled by default */
enabled = false;
server = "";
id = 0;
};
/* Include external handlers */
#include "conf.d/handlers.conf"

View File

@@ -0,0 +1,11 @@
[Unit]
Description=SWUpdate daemon
Documentation=https://sbabic.github.io/swupdate/
After=network.target
[Service]
ExecStart=/usr/bin/swupdate -w "-r /var/www/swupdate" -k /etc/swupdate-public.pem -i "board=raspberrypi3" -u "stable"
KillMode=mixed
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,37 @@
# U-Boot environment variables for A/B boot system
# Default variables for first boot - these will be modified during operation
# Active partition (A or B)
active_part=A
active_root=/dev/mmcblk0p2
inactive_part=B
inactive_root=/dev/mmcblk0p3
# Boot attempt counters
bootcount=0
bootlimit=3
# Default bootcmd
bootcmd=run bootcmd_${active_part}
# Kernel boot arguments
bootargs=console=ttyAMA0,115200 console=tty1 root=${active_root} rootwait
# Commands for booting from A or B partitions
bootcmd_A=setenv bootargs console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootwait; load mmc 0:1 ${kernel_addr_r} zImage; load mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}
bootcmd_B=setenv bootargs console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 rootwait; load mmc 0:1 ${kernel_addr_r} zImage; load mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}
# Fallback logic for failed boots
altbootcmd=if test ${active_part} = A; then setenv active_part B; setenv active_root /dev/mmcblk0p3; setenv inactive_part A; setenv inactive_root /dev/mmcblk0p2; else setenv active_part A; setenv active_root /dev/mmcblk0p2; setenv inactive_part B; setenv inactive_root /dev/mmcblk0p3; fi; setenv bootcount 0; saveenv; run bootcmd
# Memory addresses
kernel_addr_r=0x01000000
fdt_addr_r=0x02000000
# Board name
board_name=rpi3
# Network configuration (DHCP)
autoload=no
ethact=smi
ethaddr_sdio0=00:44:55:66:77:88

View File

@@ -0,0 +1,20 @@
# Disable EFI capsule which requires GnuTLS
CONFIG_EFI_CAPSULE=n
CONFIG_EFI_CAPSULE_ON_DISK=n
CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=n
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=n
CONFIG_EFI_CAPSULE_AUTHENTICATE=n
# Ensure the basic features we need are enabled
CONFIG_ENV_IS_IN_FAT=y
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
CONFIG_CMD_USB=y
CONFIG_CMD_FS_GENERIC=y
# Explicitly enable UART
CONFIG_BAUDRATE=115200
CONFIG_SERIAL=y
CONFIG_SERIAL_PRESENT=y
CONFIG_CONS_INDEX=0
CONFIG_OF_STDOUT_VIA_ALIAS=y

View File

View File

@@ -0,0 +1,105 @@
# Architecture
# Use 32-bit ARM mode for compatibility with U-Boot (64-bit mode causes build errors)
# BR2_arm=y
# BR2_cortex_a53=y
# BR2_ARM_FPU_NEON_VFPV4=y
BR2_aarch64=y
BR2_ARM_FPU_VFPV4=y
# Linux headers
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_6=y
# Kernel
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,576cc10e1ed50a9eacffc7a05c796051d7343ea4)/linux-576cc10e1ed50a9eacffc7a05c796051d7343ea4.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi3"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2710-rpi-3-b broadcom/bcm2710-rpi-3-b-plus broadcom/bcm2710-rpi-cm3"
BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
# Filesystem
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
BR2_TARGET_ROOTFS_EXT2_SIZE="256M"
# Bootloader
BR2_TARGET_UBOOT=y
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
#BR2_TARGET_UBOOT_CUSTOM_VERSION=y
#BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2023.07.02"
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="rpi_3"
BR2_TARGET_UBOOT_NEEDS_DTC=y
BR2_TARGET_UBOOT_NEEDS_PYTHON3=y
BR2_TARGET_UBOOT_NEEDS_PYLIBFDT=y
BR2_TARGET_UBOOT_FORMAT_BIN=y
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/uboot.config"
BR2_PACKAGE_UBOOT_TOOLS=y
BR2_PACKAGE_UBOOT_TOOLS_MKIMAGE=y
BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y
BR2_PACKAGE_UBOOT_TOOLS_BOOT_SCRIPT=y
BR2_PACKAGE_UBOOT_TOOLS_BOOT_SCRIPT_SOURCE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/boot.scr.txt"
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE=y
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE_SOURCE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/uboot-env.txt"
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE_SIZE="0x20000"
# Raspberry Pi firmware
BR2_PACKAGE_RPI_FIRMWARE=y
BR2_PACKAGE_RPI_FIRMWARE_BOOTCODE_BIN=y
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI=y
BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/config.txt"
# Image creation
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/post-image.sh"
# SWUpdate
BR2_PACKAGE_SWUPDATE=y
BR2_PACKAGE_SWUPDATE_CONFIG="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/swupdate.config"
BR2_PACKAGE_SWUPDATE_WEBSERVER=y
BR2_PACKAGE_SWUPDATE_INSTALL_WEBSITE=y
# Custom swupdate-scripts package
BR2_PACKAGE_SWUPDATE_SCRIPTS=y
# Required dependencies
BR2_PACKAGE_LIBCURL=y
BR2_PACKAGE_LIBCURL_OPENSSL=y
BR2_PACKAGE_LIBCONFIG=y
BR2_PACKAGE_LIBARCHIVE=y
BR2_PACKAGE_JSON_C=y
BR2_PACKAGE_LIBUBOOTENV=y
BR2_PACKAGE_LIBUBOOTENV_TARGET=y
# Utilities
BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y
BR2_PACKAGE_XZ=y
BR2_PACKAGE_KMOD=y
BR2_PACKAGE_KMOD_TOOLS=y
BR2_PACKAGE_UTIL_LINUX=y
BR2_PACKAGE_UTIL_LINUX_LIBBLKID=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
# Network
BR2_SYSTEM_DHCP="eth0"
BR2_PACKAGE_DHCPCD=y
BR2_PACKAGE_ETHTOOL=y
BR2_PACKAGE_DROPBEAR=y
# System
BR2_TARGET_GENERIC_HOSTNAME="auracaster"
BR2_TARGET_GENERIC_ISSUE="Welcome to Auracaster System"
BR2_INIT_SYSTEMD=y
BR2_SYSTEM_DEFAULT_PATH="/bin:/sbin:/usr/bin:/usr/sbin"
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/rootfs_overlay"
BR2_ROOTFS_USERS_TABLES="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/users.txt"
# No duplicate needed - already defined above
# Host tools
BR2_PACKAGE_HOST_DOSFSTOOLS=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_MTOOLS=y
BR2_PACKAGE_HOST_GNUTLS=y
BR2_PACKAGE_HOST_UBOOT_TOOLS=y

109
example/create-update-package.sh Executable file
View File

@@ -0,0 +1,109 @@
#!/bin/bash
#
# Script to create SWUpdate update package for A/B system
# This demonstrates the format of a SWUpdate package for A/B partitioning
set -e
# Configuration
BUILDROOT_DIR="../buildroot"
OUTPUT_DIR="$BUILDROOT_DIR/output"
BINARIES_DIR="$OUTPUT_DIR/images"
ROOTFS_FILE="$BINARIES_DIR/rootfs.ext4"
SWU_FILE="auracaster-update.swu"
SW_VERSION="1.0.1"
SW_DESCRIPTION="example/sw-description"
# Check if necessary files exist
if [ ! -f "$ROOTFS_FILE" ]; then
echo "Error: rootfs.ext4 not found at $ROOTFS_FILE"
echo "You need to build the project first using:"
echo "cd $BUILDROOT_DIR && make BR2_EXTERNAL=../auracaster-system auracaster_raspberrypi3_swupdate_defconfig && make"
exit 1
fi
# Create temporary directory
TEMP_DIR=$(mktemp -d)
echo "Creating update package in $TEMP_DIR"
# Create sw-description file
cat > $SW_DESCRIPTION << EOF
software = {
version = "$SW_VERSION";
raspberrypi3 = {
hardware-compatibility: [ "1.0" ];
/* We have 2 systems, A and B */
stable = {
/* Selection based on U-Boot variable 'active_part' */
/* If active_part == A, then use B for update */
/* If active_part == B, then use A for update */
/* Update copy based on active_part variable */
copy1 = {
/* Install on the inactive partition */
images: (
{
filename = "rootfs.ext4";
device = "/dev/mmcblk0p\${inactive_part == "A" ? "2" : "3"}";
type = "raw";
}
);
/* Update U-Boot environment to boot from the updated partition */
uboot: (
{
name = "bootcount";
value = "0";
},
{
name = "upgrade_available";
value = "1";
},
{
name = "active_part";
value = "\${inactive_part}";
},
{
name = "active_root";
value = "\${inactive_root}";
},
{
name = "inactive_part";
value = "\${active_part}";
},
{
name = "inactive_root";
value = "\${active_root}";
}
);
};
};
};
}
EOF
# Copy required files to temp directory
cp $ROOTFS_FILE $TEMP_DIR/
cp $SW_DESCRIPTION $TEMP_DIR/
# Create update package
echo "Creating SWUpdate package $SWU_FILE"
(cd $TEMP_DIR && \
for i in sw-description rootfs.ext4; do
echo $i;
done | cpio -ov -H crc > ../$SWU_FILE)
# Clean up
rm -rf $TEMP_DIR
echo "Update package created: $SWU_FILE"
echo "To apply this update:"
echo "1. Boot the Raspberry Pi with the SD card image"
echo "2. Access the web interface at http://<raspberry-pi-ip>:8080"
echo "3. Upload $SWU_FILE to update the inactive partition"
echo "4. After update completes, reboot the device"
echo "5. The device will boot from the updated partition"
exit 0

2
external.desc Normal file
View File

@@ -0,0 +1,2 @@
name: AURACASTER_SYSTEM
desc: Auracaster System with SWUpdate A/B layout for Raspberry Pi 3

2
external.mk Normal file
View File

@@ -0,0 +1,2 @@
# Include custom package makefiles
include $(sort $(wildcard $(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/package/*/*.mk))

169
flash_sdcard.sh Executable file
View File

@@ -0,0 +1,169 @@
#!/bin/bash
#
# Script to flash the Auracaster System image to an SD card
# This script must be run with sudo privileges
set -e
# Configuration
BUILDROOT_DIR="../buildroot"
IMAGE_FILE="$BUILDROOT_DIR/output/images/sdcard.img"
AUTO_YES=false
# Parse command line arguments
while getopts "y" opt; do
case $opt in
y)
AUTO_YES=true
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
# Check if script is run as root
if [ "$(id -u)" -ne 0 ]; then
echo "Error: This script must be run as root (sudo)."
exit 1
fi
# Check if image exists
if [ ! -f "$IMAGE_FILE" ]; then
echo "Error: Image file not found at $IMAGE_FILE"
echo "You need to build the project first."
exit 1
fi
# Find SD cards (both removable devices and mmcblk devices)
echo "Looking for SD cards..."
echo
# Get list of potential SD cards (both removable devices and mmcblk devices)
SD_CARDS=$(lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | grep -v "loop" | grep -E '(1$|mmcblk)' | awk '{print $1}')
SD_CARD_COUNT=$(echo "$SD_CARDS" | grep -v "^$" | wc -l)
if [ "$SD_CARD_COUNT" -eq 0 ]; then
echo "No SD cards found. Please insert an SD card and try again."
exit 1
fi
# Display available SD cards
echo "Available SD cards:"
echo
lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | head -n 1
lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | grep -v "loop" | grep -E '(1$|mmcblk)'
echo
# Safety check - get list of internal disks to avoid (exclude mmcblk devices from this check)
INTERNAL_DISKS=$(lsblk -d -o NAME,RM | grep -E '0$' | grep -v "mmcblk" | awk '{print $1}')
# Select SD card
DEVICE=""
if [ "$SD_CARD_COUNT" -eq 1 ]; then
DEVICE=$(echo "$SD_CARDS" | tr -d '[:space:]')
echo "Found single SD card: /dev/$DEVICE"
else
echo "Multiple SD cards found. Please select which one to use:"
select DEVICE in $SD_CARDS; do
if [ -n "$DEVICE" ]; then
break
else
echo "Invalid selection. Please try again."
fi
done
fi
# Safety check - ensure we're not flashing to an internal disk
if echo "$INTERNAL_DISKS" | grep -q "$DEVICE"; then
echo "ERROR: Selected device /dev/$DEVICE appears to be an internal disk!"
echo "This script will only flash to removable devices or mmcblk devices for safety."
exit 1
fi
# Validate device exists
if [[ "$DEVICE" == mmcblk* ]]; then
DEV_PATH="/dev/$DEVICE"
else
DEV_PATH="/dev/$DEVICE"
fi
if [ ! -b "$DEV_PATH" ]; then
echo "Error: Device $DEV_PATH does not exist or is not a block device."
exit 1
fi
# Double-check with clear warning
echo
echo "You are about to erase ALL DATA on $DEV_PATH and write the Auracaster System image to it."
echo "This operation cannot be undone."
echo
# Check if pv is available for better progress display
if command -v pv >/dev/null 2>&1; then
# Get image size for pv
IMAGE_SIZE=$(stat -c %s "$IMAGE_FILE")
# Show the command that will be executed with pv
FLASH_COMMAND="pv -s $IMAGE_SIZE \"$IMAGE_FILE\" | dd of=\"$DEV_PATH\" bs=4M conv=fsync oflag=direct"
echo "The following command will be executed (with progress bar):"
echo "$FLASH_COMMAND"
else
# Fallback to dd with status=progress
FLASH_COMMAND="dd if=\"$IMAGE_FILE\" of=\"$DEV_PATH\" bs=4M status=progress conv=fsync oflag=direct"
echo "The following command will be executed:"
echo "$FLASH_COMMAND"
echo "For better progress visualization, consider installing 'pv' (Pipe Viewer)."
fi
echo
if [ "$AUTO_YES" = true ]; then
CONFIRM="y"
echo "Auto-confirming with -y flag"
else
read -p "Are you ABSOLUTELY SURE you want to continue? (y/n): " CONFIRM
if [ "$CONFIRM" != "y" ]; then
echo "Operation cancelled."
exit 0
fi
fi
# Unmount any partitions on the device
echo "Unmounting any mounted partitions on $DEV_PATH..."
if [[ "$DEVICE" == mmcblk* ]]; then
for partition in $(lsblk -n -o NAME | grep "^$DEVICE"); do
if [ "$partition" != "$DEVICE" ]; then
umount "/dev/$partition" 2>/dev/null || true
fi
done
else
for partition in $(lsblk -n -o NAME /dev/$DEVICE | grep -v "^$DEVICE$"); do
umount "/dev/$partition" 2>/dev/null || true
done
fi
# Flash the image
echo "Flashing image to $DEV_PATH..."
echo "This may take several minutes. Please wait..."
echo
# Execute the flashing command
eval "$FLASH_COMMAND"
# Sync to ensure all writes are complete
sync
echo
echo "Flash complete!"
echo
# Remind user to eject the card safely
echo "You can now safely remove the SD card."
echo "1. Insert the SD card into your Raspberry Pi 3"
echo "2. Power on the device"
echo "3. Access the SWUpdate web interface at http://<raspberry-pi-ip>:8080"
echo
exit 0

View File

@@ -0,0 +1,8 @@
config BR2_PACKAGE_SWUPDATE_SCRIPTS
bool "swupdate-scripts"
select BR2_PACKAGE_SWUPDATE
help
Custom scripts for SWUpdate A/B partitioning system.
Provides scripts to manage the A/B partition system and
facilitate software updates.

View File

@@ -0,0 +1,119 @@
/* Custom CSS for SWUpdate Web Interface */
body {
font-family: 'Roboto', Arial, sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 0;
}
.header {
background-color: #2c3e50;
color: white;
padding: 15px;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 24px;
}
.upload-form {
background-color: white;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
margin: 20px auto;
max-width: 600px;
padding: 20px;
}
.upload-form h2 {
color: #2c3e50;
margin-top: 0;
}
.progress-container {
background-color: white;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
margin: 20px auto;
max-width: 600px;
padding: 20px;
}
.progress-bar {
background-color: #f0f0f0;
border-radius: 4px;
height: 20px;
margin: 10px 0;
overflow: hidden;
}
.progress-bar-inner {
background-color: #27ae60;
height: 100%;
transition: width 0.3s ease-in-out;
width: 0%;
}
.status {
font-weight: bold;
margin: 10px 0;
}
.btn {
background-color: #3498db;
border: none;
border-radius: 4px;
color: white;
cursor: pointer;
font-size: 16px;
padding: 10px 15px;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #2980b9;
}
.btn-success {
background-color: #27ae60;
}
.btn-success:hover {
background-color: #219955;
}
.btn-danger {
background-color: #e74c3c;
}
.btn-danger:hover {
background-color: #c0392b;
}
.system-info {
background-color: white;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
margin: 20px auto;
max-width: 600px;
padding: 20px;
}
.system-info h2 {
color: #2c3e50;
margin-top: 0;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.info-label {
font-weight: bold;
}

View File

@@ -0,0 +1,154 @@
/**
* Custom JavaScript for SWUpdate Web Interface
* Enhances the default web interface with additional functionality
*/
// Wait for DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Add custom header
addHeader();
// Add system information section
addSystemInfo();
// Enhance progress display
enhanceProgressDisplay();
// Initialize update status polling
initStatusPolling();
});
/**
* Adds a custom header to the page
*/
function addHeader() {
const header = document.createElement('div');
header.className = 'header';
header.innerHTML = '<h1>Auracaster System Update</h1>';
const body = document.body;
body.insertBefore(header, body.firstChild);
}
/**
* Adds system information section to the page
*/
function addSystemInfo() {
const systemInfo = document.createElement('div');
systemInfo.className = 'system-info';
systemInfo.innerHTML = `
<h2>System Information</h2>
<div class="info-row">
<span class="info-label">Device:</span>
<span class="info-value">Raspberry Pi 3</span>
</div>
<div class="info-row">
<span class="info-label">Active Partition:</span>
<span class="info-value" id="active-partition">Loading...</span>
</div>
<div class="info-row">
<span class="info-label">Current Version:</span>
<span class="info-value" id="current-version">Loading...</span>
</div>
<div class="info-row">
<span class="info-label">Last Update:</span>
<span class="info-value" id="last-update">Loading...</span>
</div>
<div class="actions" style="margin-top: 15px;">
<button class="btn" id="refresh-info">Refresh</button>
</div>
`;
// Insert before the upload form
const uploadForm = document.querySelector('form');
if (uploadForm) {
uploadForm.parentNode.insertBefore(systemInfo, uploadForm);
} else {
document.body.appendChild(systemInfo);
}
// Add event listener for refresh button
document.getElementById('refresh-info').addEventListener('click', fetchSystemInfo);
// Initial fetch of system info
fetchSystemInfo();
}
/**
* Fetches system information via AJAX
*/
function fetchSystemInfo() {
// In a real implementation, this would call an API endpoint
// For now, we'll use dummy data that would typically come from swupdate-check.sh
const activePartition = Math.random() > 0.5 ? 'A' : 'B';
const version = '1.0.' + Math.floor(Math.random() * 10);
const lastUpdate = new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toLocaleString();
document.getElementById('active-partition').textContent = activePartition;
document.getElementById('current-version').textContent = version;
document.getElementById('last-update').textContent = lastUpdate;
}
/**
* Enhances the progress display with better visuals
*/
function enhanceProgressDisplay() {
// Find the progress container (assuming it exists in the default UI)
const progressContainer = document.querySelector('.progress');
if (!progressContainer) return;
// Create enhanced progress container
const enhancedProgress = document.createElement('div');
enhancedProgress.className = 'progress-container';
enhancedProgress.innerHTML = `
<h2>Update Progress</h2>
<div class="progress-bar">
<div class="progress-bar-inner" id="progress-bar"></div>
</div>
<div class="status" id="progress-status">Waiting for update...</div>
`;
// Replace the original progress container
progressContainer.parentNode.replaceChild(enhancedProgress, progressContainer);
}
/**
* Initializes polling for update status
*/
function initStatusPolling() {
// In a real implementation, this would poll an API endpoint
// For demonstration, we'll simulate progress updates
let progress = 0;
const updateProgress = setInterval(() => {
// This would normally only run during an active update
// For demo purposes, it increments regardless
if (progress < 100) {
progress += Math.floor(Math.random() * 5);
if (progress > 100) progress = 100;
const progressBar = document.getElementById('progress-bar');
const progressStatus = document.getElementById('progress-status');
if (progressBar) {
progressBar.style.width = progress + '%';
}
if (progressStatus) {
if (progress < 30) {
progressStatus.textContent = 'Downloading update...';
} else if (progress < 60) {
progressStatus.textContent = 'Verifying update...';
} else if (progress < 90) {
progressStatus.textContent = 'Installing to inactive partition...';
} else if (progress < 100) {
progressStatus.textContent = 'Finalizing update...';
} else {
progressStatus.textContent = 'Update complete! Reboot to apply.';
clearInterval(updateProgress);
}
}
}
}, 1000);
}

View File

@@ -0,0 +1,40 @@
/* SWUpdate handlers configuration */
/* Enable raw partition handler */
raw: {
/* Partitions that can be updated */
partitions = (
{
/* Inactive partition will be updated */
type = "ubipartition";
name = "inactive";
/* This is a key-value substitution */
/* Will be replaced with the actual inactive partition */
device = "${inactive_part}";
}
);
};
/* Enable U-Boot environment handler */
bootenv: {
/* U-Boot environment variables to update */
bootloader = {
/* Where the U-Boot environment is stored */
environment = {
/* DeviceA = PART, DeviceB = FILE */
device = "/dev/mmcblk0p1";
file = "uboot-env.img";
};
/* Variables to set after successful update */
set-variables = (
{name = "bootcount"; value = "0";},
{name = "upgrade_available"; value = "1";},
{name = "active_part"; value = "${inactive_part}";},
{name = "active_root"; value = "${inactive_root}";},
{name = "inactive_part"; value = "${active_part}";},
{name = "inactive_root"; value = "${active_root}";}
);
};
};

View File

@@ -0,0 +1,110 @@
#!/bin/sh
# A/B partition management helper for SWUpdate
# Print usage
usage() {
echo "Usage: $0 [OPTION]"
echo "Manage A/B partitioning system for SWUpdate"
echo ""
echo "Options:"
echo " -s, --status Show current partition status"
echo " -t, --toggle Toggle active/inactive partitions"
echo " -c, --commit Commit current boot (reset bootcount)"
echo " -r, --reboot Reboot to apply changes"
echo " -h, --help Show this help message"
exit 1
}
# Show current status
show_status() {
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
INACTIVE_PART=$(fw_printenv -n inactive_part 2>/dev/null || echo "Unknown")
BOOTCOUNT=$(fw_printenv -n bootcount 2>/dev/null || echo "Unknown")
BOOTLIMIT=$(fw_printenv -n bootlimit 2>/dev/null || echo "Unknown")
echo "A/B Partition Status:"
echo " Active partition: $ACTIVE_PART (/dev/mmcblk0p$([ "$ACTIVE_PART" = "A" ] && echo "2" || echo "3"))"
echo " Inactive partition: $INACTIVE_PART (/dev/mmcblk0p$([ "$INACTIVE_PART" = "A" ] && echo "2" || echo "3"))"
echo " Boot count: $BOOTCOUNT/$BOOTLIMIT"
# Check if an update is pending
if [ -e /tmp/swupdate.done ]; then
echo " Update status: Completed, pending reboot"
else
echo " Update status: No recent update"
fi
}
# Toggle active/inactive partitions
toggle_partitions() {
ACTIVE_PART=$(fw_printenv -n active_part)
INACTIVE_PART=$(fw_printenv -n inactive_part)
if [ "$ACTIVE_PART" = "A" ]; then
NEW_ACTIVE="B"
NEW_INACTIVE="A"
NEW_ACTIVE_ROOT="/dev/mmcblk0p3"
NEW_INACTIVE_ROOT="/dev/mmcblk0p2"
else
NEW_ACTIVE="A"
NEW_INACTIVE="B"
NEW_ACTIVE_ROOT="/dev/mmcblk0p2"
NEW_INACTIVE_ROOT="/dev/mmcblk0p3"
fi
echo "Switching active partition from $ACTIVE_PART to $NEW_ACTIVE"
fw_setenv active_part "$NEW_ACTIVE"
fw_setenv inactive_part "$NEW_INACTIVE"
fw_setenv active_root "$NEW_ACTIVE_ROOT"
fw_setenv inactive_root "$NEW_INACTIVE_ROOT"
fw_setenv bootcount 0
echo "Partition switch complete. Reboot to apply changes."
}
# Commit current boot (reset bootcount)
commit_boot() {
echo "Committing current boot by resetting bootcount"
fw_setenv bootcount 0
echo "Bootcount reset to 0"
}
# Reboot system
reboot_system() {
echo "Rebooting system..."
sync
reboot
}
# Parse command line arguments
if [ $# -eq 0 ]; then
usage
fi
while [ $# -gt 0 ]; do
case "$1" in
-s|--status)
show_status
;;
-t|--toggle)
toggle_partitions
;;
-c|--commit)
commit_boot
;;
-r|--reboot)
reboot_system
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1"
usage
;;
esac
shift
done
exit 0

View File

@@ -0,0 +1,69 @@
#!/bin/sh
# Helper script to check for updates and system status
# Configuration
UPDATE_SERVER=""
BOARD_NAME="raspberrypi3"
SW_VERSION=$(cat /etc/sw-version 2>/dev/null || echo "1.0.0")
# Get current system state
get_current_status() {
# Get active partition
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
echo "Active partition: $ACTIVE_PART"
# Get inactive partition
INACTIVE_PART=$(fw_printenv -n inactive_part 2>/dev/null || echo "Unknown")
echo "Inactive partition: $INACTIVE_PART"
# Get boot count
BOOT_COUNT=$(fw_printenv -n bootcount 2>/dev/null || echo "Unknown")
echo "Boot count: $BOOT_COUNT"
# Check if system was recently updated
if [ -e /tmp/swupdate.done ]; then
echo "System was updated"
UPDATED=1
else
echo "No recent update"
UPDATED=0
fi
# Check if there's an update available (if server is configured)
if [ -n "$UPDATE_SERVER" ]; then
echo "Checking for updates from $UPDATE_SERVER..."
# Simple curl check - in production, this would be more robust
if curl -s -f "$UPDATE_SERVER/api/check?board=$BOARD_NAME&version=$SW_VERSION" >/dev/null; then
echo "Update available"
UPDATE_AVAILABLE=1
else
echo "No update available"
UPDATE_AVAILABLE=0
fi
else
echo "No update server configured"
UPDATE_AVAILABLE=0
fi
}
# Reset update status
reset_update_status() {
echo "Resetting update status"
rm -f /tmp/swupdate.done
}
# Main
case "$1" in
status)
get_current_status
;;
reset)
reset_update_status
;;
*)
echo "Usage: $0 {status|reset}"
exit 1
;;
esac
exit 0

View File

@@ -0,0 +1,62 @@
#!/bin/sh
# Monitor progress of SWUpdate and report it
TMPDIR="/tmp"
FIFO="$TMPDIR/swupdate-progress"
# Create FIFO if it doesn't exist
if [ ! -e "$FIFO" ]; then
mkfifo "$FIFO"
fi
# If no arguments, print usage
if [ $# -eq 0 ]; then
echo "Usage: $0 <command>"
echo "Commands:"
echo " monitor - Monitor progress of an update"
echo " status - Show current status"
exit 1
fi
case "$1" in
monitor)
# Start monitoring FIFO
while true; do
if read line <"$FIFO"; then
echo "$line"
# Extract progress percentage
PROGRESS=$(echo "$line" | grep -o '[0-9]*%' | grep -o '[0-9]*')
if [ -n "$PROGRESS" ] && [ "$PROGRESS" = "100" ]; then
echo "Update complete!"
break
fi
# Check for error messages
if echo "$line" | grep -q "FAILURE"; then
echo "Update failed!"
break
fi
else
# FIFO closed
echo "Connection closed"
break
fi
done
;;
status)
# Show which partition is active
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
echo "Active partition: $ACTIVE_PART"
# Show update status if available
if [ -e /tmp/swupdate.done ]; then
echo "Last update: Successful"
else
echo "No recent update"
fi
;;
*)
echo "Unknown command: $1"
exit 1
;;
esac
exit 0

View File

@@ -0,0 +1,21 @@
################################################################################
#
# swupdate-scripts
#
################################################################################
SWUPDATE_SCRIPTS_VERSION = 1.0
SWUPDATE_SCRIPTS_SITE = $(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/package/swupdate-scripts/files
SWUPDATE_SCRIPTS_SITE_METHOD = local
define SWUPDATE_SCRIPTS_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/swupdate-progress.sh $(TARGET_DIR)/usr/bin/swupdate-progress
$(INSTALL) -D -m 0755 $(@D)/swupdate-check.sh $(TARGET_DIR)/usr/bin/swupdate-check
$(INSTALL) -D -m 0755 $(@D)/swupdate-ab-helper.sh $(TARGET_DIR)/usr/bin/swupdate-ab-helper
$(INSTALL) -D -m 0644 $(@D)/handlers.conf $(TARGET_DIR)/etc/swupdate/conf.d/handlers.conf
mkdir -p $(TARGET_DIR)/var/www/swupdate/custom
$(INSTALL) -D -m 0644 $(@D)/custom.js $(TARGET_DIR)/var/www/swupdate/custom/custom.js
$(INSTALL) -D -m 0644 $(@D)/custom.css $(TARGET_DIR)/var/www/swupdate/custom/custom.css
endef
$(eval $(generic-package))