Build optimization: pre-built PM3 binaries, ARM64 CI, base image caching
Replace PM3 compile-from-source in pi-gen with pre-built tarball extraction (saves 43-58 min). Merge stagePM3 into stageDangerousPi as 02-pm3-install substage, renumber all subsequent substages. Switch CI PM3 build to native ARM64 runner (ubuntu-24.04-arm64) eliminating QEMU overhead. Add weekly base-image workflow for pre-baking stages 0-2. Support PM3_TARBALL, BASE_IMAGE, and APT_PROXY env vars in build-image.sh. Also includes prior Phase 5 work: theme system, design system integration, component update system, OS updates, CI build pipeline, and test results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
17
pi-gen/stageDangerousPi/00-apt-setup/00-packages
Normal file
17
pi-gen/stageDangerousPi/00-apt-setup/00-packages
Normal file
@@ -0,0 +1,17 @@
|
||||
# Consolidated package list for stageDangerousPi
|
||||
# All packages needed across substages, installed in one apt-get call
|
||||
# to avoid redundant apt-get update / Reading package lists overhead.
|
||||
|
||||
# 01-Wireless-AP: WiFi access point + reverse proxy
|
||||
hostapd
|
||||
dnsmasq
|
||||
nftables
|
||||
nginx
|
||||
|
||||
# 03-dangerous-pi: backend/frontend runtime + utilities
|
||||
nodejs
|
||||
npm
|
||||
lrzsz
|
||||
|
||||
# 04-pisugar: I2C tools for UPS battery monitoring
|
||||
i2c-tools
|
||||
@@ -7,13 +7,7 @@
|
||||
|
||||
echo "=== Setting up WiFi Access Point ==="
|
||||
|
||||
# Install required packages
|
||||
echo "Installing hostapd, dnsmasq, nginx..."
|
||||
apt-get install -y \
|
||||
hostapd \
|
||||
dnsmasq \
|
||||
nftables \
|
||||
nginx
|
||||
# Packages (hostapd, dnsmasq, nftables, nginx) installed by 00-apt-setup stage
|
||||
|
||||
# Note: We no longer use static config file for wlan0 management.
|
||||
# The wifi_manager now uses 'nmcli device set wlan0 managed yes/no' dynamically.
|
||||
|
||||
414
pi-gen/stageDangerousPi/02-pm3-install/00-run-chroot-compile.sh
Normal file
414
pi-gen/stageDangerousPi/02-pm3-install/00-run-chroot-compile.sh
Normal file
@@ -0,0 +1,414 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# Proxmark3 Client Build with Python Bindings
|
||||
# Builds firmware + client + experimental Python library for Dangerous Pi
|
||||
# Date: 2025-11-26
|
||||
|
||||
echo "=== Starting Proxmark3 build with Python bindings ==="
|
||||
|
||||
# Check if build can be skipped (manifest unchanged from previous build)
|
||||
if [ -f /tmp/SKIP_PM3_BUILD ]; then
|
||||
echo "=== PM3 build manifest unchanged — checking cached installation ==="
|
||||
DEFAULT_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 {print $1; exit}' /etc/passwd)
|
||||
DEFAULT_HOME=$(eval echo ~${DEFAULT_USER:-pi})
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/proxmark3" ] && \
|
||||
[ -f "$DEFAULT_HOME/.pm3/proxmark3/firmware/fullimage.elf" ]; then
|
||||
echo "✓ PM3 client binary present"
|
||||
echo "✓ PM3 firmware present"
|
||||
echo "=== Skipping Proxmark3 build (cached) ==="
|
||||
exit 0
|
||||
else
|
||||
echo "✗ PM3 binaries missing despite manifest match — rebuilding"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install build dependencies
|
||||
# apt-get update not needed: metadata inherited from stage0 (same build session)
|
||||
echo "Installing build dependencies..."
|
||||
apt-get install -y \
|
||||
cmake \
|
||||
python3-dev \
|
||||
swig \
|
||||
build-essential \
|
||||
libreadline-dev \
|
||||
libusb-1.0-0-dev \
|
||||
liblz4-dev \
|
||||
libbz2-dev \
|
||||
libjansson-dev \
|
||||
libc6-dev \
|
||||
pkg-config \
|
||||
git \
|
||||
gcc-arm-none-eabi \
|
||||
libnewlib-dev \
|
||||
ca-certificates \
|
||||
libssl-dev \
|
||||
libbluetooth-dev \
|
||||
libgd-dev
|
||||
|
||||
# Read pinned version config if available
|
||||
PM3_REPO="https://github.com/RfidResearchGroup/proxmark3"
|
||||
PM3_COMMIT=""
|
||||
if [ -f /tmp/pm3-version.conf ]; then
|
||||
. /tmp/pm3-version.conf
|
||||
fi
|
||||
|
||||
# Clone Proxmark3 repository
|
||||
echo "Cloning Proxmark3 repository..."
|
||||
cd /tmp
|
||||
rm -rf proxmark3 # Clean any existing clone
|
||||
git clone "$PM3_REPO" proxmark3
|
||||
cd proxmark3
|
||||
if [ -n "$PM3_COMMIT" ]; then
|
||||
echo "Checking out pinned commit: $PM3_COMMIT"
|
||||
git checkout "$PM3_COMMIT"
|
||||
fi
|
||||
|
||||
# Apply LED PWM control patch (custom Dangerous Pi feature)
|
||||
# Patch was copied to /tmp by 00-run.sh (pre-chroot script)
|
||||
echo "Applying LED PWM control patch..."
|
||||
if [ -f /tmp/led-pwm-control.patch ]; then
|
||||
patch -p1 < /tmp/led-pwm-control.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✓ LED PWM control patch applied successfully"
|
||||
else
|
||||
echo "✗ WARNING: LED PWM control patch failed to apply cleanly"
|
||||
fi
|
||||
rm /tmp/led-pwm-control.patch
|
||||
else
|
||||
echo "✗ WARNING: LED PWM control patch not found at /tmp/led-pwm-control.patch"
|
||||
fi
|
||||
|
||||
# Add Dangerous Pi branding to version string
|
||||
echo "Adding Dangerous Pi branding to version..."
|
||||
sed -i 's/^fullgitinfo="Iceman"$/fullgitinfo="Iceman\/DangerousPi"/' tools/mkversion.sh
|
||||
if grep -q 'fullgitinfo="Iceman/DangerousPi"' tools/mkversion.sh; then
|
||||
echo "✓ Version branding applied"
|
||||
else
|
||||
echo "✗ WARNING: Version branding may not have applied correctly"
|
||||
fi
|
||||
|
||||
# Build firmware (existing functionality)
|
||||
echo "Building firmware..."
|
||||
cat > Makefile.platform << EOF
|
||||
PLATFORM=PM3GENERIC
|
||||
LED_ORDER=PM3EASY
|
||||
EOF
|
||||
make clean && make -j$(nproc)
|
||||
|
||||
# Apply fixes to CMakeLists.txt for Python bindings
|
||||
# These fix undefined symbol errors in the SWIG library
|
||||
|
||||
# Fix 1: Add qrcode.c (fixes "undefined symbol: qrcode_print_matrix_utf8")
|
||||
echo "Applying qrcode fix to experimental library..."
|
||||
sed -i '/TARGET_SOURCES.*pm3rrg_rdv4_experimental/,/)/s|\(${PM3_ROOT}/client/src/wiegand_formatutils.c\)|\1\n ${PM3_ROOT}/client/src/qrcode/qrcode.c|' \
|
||||
client/experimental_lib/CMakeLists.txt
|
||||
|
||||
# Fix 2: Add pla.c (fixes "undefined symbol: pla_parse_ecp_subcommand")
|
||||
echo "Applying pla.c fix to experimental library..."
|
||||
sed -i 's|\(${PM3_ROOT}/client/src/pm3\.c\)|${PM3_ROOT}/client/src/pla.c\n \1|' \
|
||||
client/experimental_lib/CMakeLists.txt
|
||||
|
||||
# Verify the fixes were applied
|
||||
if grep -q "qrcode/qrcode.c" client/experimental_lib/CMakeLists.txt; then
|
||||
echo "✓ qrcode fix applied successfully"
|
||||
else
|
||||
echo "✗ WARNING: qrcode fix may not have applied correctly"
|
||||
fi
|
||||
|
||||
if grep -q "pla\.c" client/experimental_lib/CMakeLists.txt; then
|
||||
echo "✓ pla.c fix applied successfully"
|
||||
else
|
||||
echo "✗ WARNING: pla.c fix may not have applied correctly"
|
||||
fi
|
||||
|
||||
# Build client with Python bindings
|
||||
echo "Building PM3 client..."
|
||||
cd client
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. -DBUILD_PYTHON_LIB=ON
|
||||
make -j$(nproc)
|
||||
|
||||
# Build experimental Python library
|
||||
echo "Building experimental Python library..."
|
||||
cd ../experimental_lib
|
||||
./00make_swig.sh
|
||||
./01make_lib.sh
|
||||
|
||||
# Detect the default user (cloud-init compatible)
|
||||
# Find first user with UID >= 1000 (excluding nobody)
|
||||
DEFAULT_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 {print $1; exit}' /etc/passwd)
|
||||
if [ -z "$DEFAULT_USER" ]; then
|
||||
DEFAULT_USER="pi" # Fallback to pi if detection fails
|
||||
fi
|
||||
DEFAULT_HOME=$(eval echo ~$DEFAULT_USER)
|
||||
|
||||
echo "Detected default user: $DEFAULT_USER (home: $DEFAULT_HOME)"
|
||||
|
||||
# Create installation directories
|
||||
echo "Creating installation directories..."
|
||||
mkdir -p $DEFAULT_HOME
|
||||
mkdir -p $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts
|
||||
mkdir -p $DEFAULT_HOME/.pm3/proxmark3/firmware
|
||||
mkdir -p $DEFAULT_HOME/.pm3/proxmark3/patches
|
||||
mkdir -p $DEFAULT_HOME/.pm3/proxmark3/scripts
|
||||
|
||||
# Install client executable
|
||||
echo "Installing PM3 client..."
|
||||
cp /tmp/proxmark3/client/build/proxmark3 $DEFAULT_HOME/.pm3/proxmark3/client/
|
||||
|
||||
# Install flash utilities
|
||||
echo "Installing flash utilities..."
|
||||
cp /tmp/proxmark3/pm3-flash-all $DEFAULT_HOME/.pm3/proxmark3/
|
||||
cp /tmp/proxmark3/pm3-flash-bootrom $DEFAULT_HOME/.pm3/proxmark3/
|
||||
cp /tmp/proxmark3/pm3-flash-fullimage $DEFAULT_HOME/.pm3/proxmark3/
|
||||
chmod +x $DEFAULT_HOME/.pm3/proxmark3/pm3-flash-*
|
||||
|
||||
# Install LED PWM control patch for future rebuilds
|
||||
echo "Installing LED PWM control patch..."
|
||||
if [ -f /tmp/led-pwm-control.patch ]; then
|
||||
cp /tmp/led-pwm-control.patch $DEFAULT_HOME/.pm3/proxmark3/patches/
|
||||
echo "✓ LED PWM control patch saved for future rebuilds"
|
||||
fi
|
||||
|
||||
# Install PM3 rebuild script
|
||||
echo "Creating PM3 rebuild script..."
|
||||
cat > $DEFAULT_HOME/.pm3/proxmark3/scripts/rebuild-pm3.sh << 'REBUILD_EOF'
|
||||
#!/bin/bash
|
||||
# Rebuild Proxmark3 client and firmware with LED PWM control patch
|
||||
# Usage: ./rebuild-pm3.sh [--flash]
|
||||
|
||||
set -e
|
||||
|
||||
PM3_HOME="$HOME/.pm3/proxmark3"
|
||||
BUILD_DIR="/tmp/proxmark3-rebuild"
|
||||
PATCH_FILE="$PM3_HOME/patches/led-pwm-control.patch"
|
||||
|
||||
echo "=== Proxmark3 Rebuild Script ==="
|
||||
echo "This will rebuild the PM3 client and firmware with LED PWM control."
|
||||
echo ""
|
||||
|
||||
# Check for ARM toolchain
|
||||
if ! command -v arm-none-eabi-gcc &> /dev/null; then
|
||||
echo "ERROR: ARM toolchain not found. Install with:"
|
||||
echo " sudo apt install gcc-arm-none-eabi"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean previous build
|
||||
rm -rf "$BUILD_DIR"
|
||||
|
||||
# Clone fresh copy
|
||||
echo "Cloning Proxmark3 repository..."
|
||||
git clone --depth 1 https://github.com/RfidResearchGroup/proxmark3 "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Apply LED PWM control patch
|
||||
if [ -f "$PATCH_FILE" ]; then
|
||||
echo "Applying LED PWM control patch..."
|
||||
patch -p1 < "$PATCH_FILE"
|
||||
echo "✓ Patch applied"
|
||||
else
|
||||
echo "WARNING: LED patch not found at $PATCH_FILE"
|
||||
fi
|
||||
|
||||
# Add Dangerous Pi branding to version string
|
||||
echo "Adding Dangerous Pi branding..."
|
||||
sed -i 's/^fullgitinfo="Iceman"$/fullgitinfo="Iceman\/DangerousPi"/' tools/mkversion.sh
|
||||
|
||||
# Configure build
|
||||
echo "Configuring build..."
|
||||
cat > Makefile.platform << EOF
|
||||
PLATFORM=PM3GENERIC
|
||||
LED_ORDER=PM3EASY
|
||||
EOF
|
||||
|
||||
# Build firmware and client
|
||||
echo "Building firmware (this takes a while on Pi Zero)..."
|
||||
make clean
|
||||
make -j$(nproc)
|
||||
|
||||
# Build client with Python bindings
|
||||
echo "Building client..."
|
||||
cd client
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. -DBUILD_PYTHON_LIB=ON
|
||||
make -j$(nproc)
|
||||
|
||||
# Build experimental Python library
|
||||
echo "Building Python bindings..."
|
||||
cd ../experimental_lib
|
||||
./00make_swig.sh
|
||||
./01make_lib.sh
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Backup current installation
|
||||
echo "Backing up current installation..."
|
||||
if [ -f "$PM3_HOME/client/proxmark3" ]; then
|
||||
cp "$PM3_HOME/client/proxmark3" "$PM3_HOME/client/proxmark3.bak"
|
||||
fi
|
||||
if [ -f "$PM3_HOME/firmware/fullimage.elf" ]; then
|
||||
cp "$PM3_HOME/firmware/fullimage.elf" "$PM3_HOME/firmware/fullimage.elf.bak"
|
||||
fi
|
||||
|
||||
# Install new binaries
|
||||
echo "Installing new client..."
|
||||
cp "$BUILD_DIR/client/build/proxmark3" "$PM3_HOME/client/"
|
||||
cp "$BUILD_DIR/client/experimental_lib/build/libpm3rrg_rdv4.so" "$PM3_HOME/client/pyscripts/"
|
||||
cp "$BUILD_DIR/client/pyscripts/*.py" "$PM3_HOME/client/pyscripts/"
|
||||
|
||||
echo "Installing new firmware..."
|
||||
cp "$BUILD_DIR/bootrom/obj/bootrom.elf" "$PM3_HOME/firmware/"
|
||||
cp "$BUILD_DIR/armsrc/obj/fullimage.elf" "$PM3_HOME/firmware/"
|
||||
|
||||
# Update flash utilities
|
||||
echo "Updating flash utilities..."
|
||||
cp "$BUILD_DIR/pm3-flash-all" "$PM3_HOME/"
|
||||
cp "$BUILD_DIR/pm3-flash-bootrom" "$PM3_HOME/"
|
||||
cp "$BUILD_DIR/pm3-flash-fullimage" "$PM3_HOME/"
|
||||
chmod +x "$PM3_HOME/pm3-flash-"*
|
||||
|
||||
# Update version
|
||||
echo "Updating version info..."
|
||||
cd "$BUILD_DIR"
|
||||
git describe --always --tags > "$PM3_HOME/VERSION.txt"
|
||||
echo "Build date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> "$PM3_HOME/VERSION.txt"
|
||||
echo "Built with LED PWM control patch" >> "$PM3_HOME/VERSION.txt"
|
||||
|
||||
echo ""
|
||||
echo "=== Build Complete ==="
|
||||
echo "New client: $PM3_HOME/client/proxmark3"
|
||||
echo "New firmware: $PM3_HOME/firmware/"
|
||||
echo ""
|
||||
|
||||
# Flash if requested
|
||||
if [ "$1" == "--flash" ]; then
|
||||
echo "Flashing firmware to connected device..."
|
||||
cd "$PM3_HOME"
|
||||
./pm3-flash-all
|
||||
echo "✓ Flash complete"
|
||||
else
|
||||
echo "To flash the new firmware, run:"
|
||||
echo " cd $PM3_HOME && ./pm3-flash-all"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$BUILD_DIR"
|
||||
echo "✓ Cleanup complete"
|
||||
REBUILD_EOF
|
||||
chmod +x $DEFAULT_HOME/.pm3/proxmark3/scripts/rebuild-pm3.sh
|
||||
|
||||
# Install Python bindings
|
||||
echo "Installing Python bindings..."
|
||||
cp /tmp/proxmark3/client/experimental_lib/build/libpm3rrg_rdv4.so $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/
|
||||
cp /tmp/proxmark3/client/pyscripts/*.py $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/
|
||||
|
||||
# Create _pm3.so symlink for Python import (CRITICAL - this is what pm3.py imports)
|
||||
echo "Creating Python module symlink..."
|
||||
cd $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts
|
||||
ln -sf libpm3rrg_rdv4.so _pm3.so
|
||||
|
||||
# Install firmware files
|
||||
echo "Installing firmware files..."
|
||||
cp /tmp/proxmark3/bootrom/obj/bootrom.elf $DEFAULT_HOME/.pm3/proxmark3/firmware/
|
||||
cp /tmp/proxmark3/armsrc/obj/fullimage.elf $DEFAULT_HOME/.pm3/proxmark3/firmware/
|
||||
|
||||
# Create version file for tracking
|
||||
echo "Creating version file..."
|
||||
cd /tmp/proxmark3
|
||||
git describe --always --tags > $DEFAULT_HOME/.pm3/proxmark3/VERSION.txt
|
||||
echo "Build date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $DEFAULT_HOME/.pm3/proxmark3/VERSION.txt
|
||||
|
||||
# Set proper ownership
|
||||
echo "Setting ownership..."
|
||||
chown -R $DEFAULT_USER:$DEFAULT_USER $DEFAULT_HOME/.pm3
|
||||
|
||||
# Add Python path to environment (for systemd services)
|
||||
echo "Configuring Python path..."
|
||||
# Ensure .bashrc exists
|
||||
touch $DEFAULT_HOME/.bashrc
|
||||
if ! grep -q "PYTHONPATH.*\.pm3" $DEFAULT_HOME/.bashrc; then
|
||||
echo 'export PYTHONPATH=$HOME/.pm3/proxmark3/client/pyscripts:$PYTHONPATH' >> $DEFAULT_HOME/.bashrc
|
||||
fi
|
||||
|
||||
# Verify installation
|
||||
echo "Verifying installation..."
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/client/proxmark3 ]; then
|
||||
echo "✓ Client executable installed"
|
||||
else
|
||||
echo "✗ ERROR: Client executable not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify library architecture matches the target platform
|
||||
echo "Verifying library architecture..."
|
||||
LIB_ARCH=$(file $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/libpm3rrg_rdv4.so | grep -o 'ARM aarch64\|x86-64\|ARM,')
|
||||
EXPECTED_ARCH="ARM aarch64"
|
||||
if [ "$LIB_ARCH" = "$EXPECTED_ARCH" ]; then
|
||||
echo "✓ Library architecture correct: $LIB_ARCH"
|
||||
else
|
||||
echo "✗ ERROR: Library architecture mismatch!"
|
||||
echo " Expected: $EXPECTED_ARCH"
|
||||
echo " Got: $LIB_ARCH"
|
||||
echo " The library was built for the wrong architecture."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/pm3.py ]; then
|
||||
echo "✓ Python module installed"
|
||||
else
|
||||
echo "✗ ERROR: Python module not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/_pm3.so ]; then
|
||||
echo "✓ Python bindings library installed (_pm3.so)"
|
||||
else
|
||||
echo "✗ ERROR: Python bindings library not found (_pm3.so)"
|
||||
echo " Expected symlink: _pm3.so -> libpm3rrg_rdv4.so"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/firmware/fullimage.elf ]; then
|
||||
echo "✓ Firmware files installed"
|
||||
else
|
||||
echo "✗ ERROR: Firmware files not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/pm3-flash-all ]; then
|
||||
echo "✓ Flash utilities installed"
|
||||
else
|
||||
echo "✗ WARNING: Flash utilities not found (flashing from UI will not work)"
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/patches/led-pwm-control.patch ]; then
|
||||
echo "✓ LED PWM control patch saved"
|
||||
else
|
||||
echo "✗ WARNING: LED PWM control patch not saved"
|
||||
fi
|
||||
|
||||
if [ -f $DEFAULT_HOME/.pm3/proxmark3/scripts/rebuild-pm3.sh ]; then
|
||||
echo "✓ Rebuild script installed"
|
||||
else
|
||||
echo "✗ WARNING: Rebuild script not installed"
|
||||
fi
|
||||
|
||||
# Save build manifest for future cache checks
|
||||
if [ -f /tmp/pm3-build-manifest ]; then
|
||||
mkdir -p /opt/dangerous-pi
|
||||
cp /tmp/pm3-build-manifest /opt/dangerous-pi/.pm3-build-manifest
|
||||
echo "✓ Build manifest saved for cache"
|
||||
fi
|
||||
|
||||
# Print summary
|
||||
echo "=== Proxmark3 build complete ==="
|
||||
echo "Installation location: $DEFAULT_HOME/.pm3/proxmark3/"
|
||||
echo "Client: $DEFAULT_HOME/.pm3/proxmark3/client/proxmark3"
|
||||
echo "Flash utils: $DEFAULT_HOME/.pm3/proxmark3/pm3-flash-all"
|
||||
echo "Python: $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/pm3.py"
|
||||
echo "Firmware: $DEFAULT_HOME/.pm3/proxmark3/firmware/"
|
||||
cat $DEFAULT_HOME/.pm3/proxmark3/VERSION.txt
|
||||
|
||||
echo "✓ Proxmark3 installation successful"
|
||||
282
pi-gen/stageDangerousPi/02-pm3-install/00-run-chroot.sh
Normal file
282
pi-gen/stageDangerousPi/02-pm3-install/00-run-chroot.sh
Normal file
@@ -0,0 +1,282 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# Install Proxmark3 from pre-built tarball or compile from source as fallback.
|
||||
#
|
||||
# Pre-built tarball: extracted from /tmp/pm3-prebuilt.tar.gz (staged by 00-run.sh)
|
||||
# Compile fallback: triggered when /tmp/PM3_COMPILE_FROM_SOURCE exists
|
||||
|
||||
echo "=== Proxmark3 Installation ==="
|
||||
|
||||
# --- Check if we need to compile from source (fallback) ---
|
||||
if [ -f /tmp/PM3_COMPILE_FROM_SOURCE ]; then
|
||||
echo "No pre-built tarball available — compiling from source"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
if [ -f "${SCRIPT_DIR}/00-run-chroot-compile.sh" ]; then
|
||||
exec "${SCRIPT_DIR}/00-run-chroot-compile.sh"
|
||||
else
|
||||
echo "ERROR: Compile fallback script not found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Pre-built tarball installation ---
|
||||
if [ ! -f /tmp/pm3-prebuilt.tar.gz ]; then
|
||||
echo "ERROR: PM3 tarball not found at /tmp/pm3-prebuilt.tar.gz"
|
||||
echo "Set PM3_TARBALL env var or place a tarball in 02-pm3-install/files/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install runtime dependencies only (no build tools needed)
|
||||
echo "Installing runtime dependencies..."
|
||||
apt-get install -y \
|
||||
libreadline8t64 \
|
||||
libusb-1.0-0 \
|
||||
liblz4-1 \
|
||||
libbz2-1.0 \
|
||||
libjansson4 \
|
||||
libgd3t64 \
|
||||
libssl3t64 \
|
||||
libbluetooth3
|
||||
|
||||
# Detect the default user (first UID >= 1000, excluding nobody)
|
||||
DEFAULT_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 {print $1; exit}' /etc/passwd)
|
||||
if [ -z "$DEFAULT_USER" ]; then
|
||||
DEFAULT_USER="pi"
|
||||
fi
|
||||
DEFAULT_HOME=$(eval echo ~$DEFAULT_USER)
|
||||
echo "Installing for user: $DEFAULT_USER (home: $DEFAULT_HOME)"
|
||||
|
||||
# Create installation directory
|
||||
mkdir -p "$DEFAULT_HOME/.pm3/proxmark3"
|
||||
|
||||
# Extract pre-built tarball
|
||||
# Tarball structure: pm3/{client/,firmware/,patches/,scripts/,pm3-flash-*,COMPONENT_VERSION}
|
||||
echo "Extracting PM3 tarball..."
|
||||
tar -xzf /tmp/pm3-prebuilt.tar.gz -C "$DEFAULT_HOME/.pm3/proxmark3" --strip-components=1
|
||||
|
||||
# Ensure _pm3.so symlink exists (critical for Python import)
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/libpm3rrg_rdv4.so" ] && \
|
||||
[ ! -f "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/_pm3.so" ]; then
|
||||
echo "Creating _pm3.so symlink..."
|
||||
cd "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts"
|
||||
ln -sf libpm3rrg_rdv4.so _pm3.so
|
||||
fi
|
||||
|
||||
# Ensure flash utilities are executable
|
||||
chmod +x "$DEFAULT_HOME/.pm3/proxmark3/pm3-flash-"* 2>/dev/null || true
|
||||
|
||||
# Install PM3 rebuild script (for on-device source rebuilds)
|
||||
echo "Installing rebuild script..."
|
||||
mkdir -p "$DEFAULT_HOME/.pm3/proxmark3/scripts"
|
||||
cat > "$DEFAULT_HOME/.pm3/proxmark3/scripts/rebuild-pm3.sh" << 'REBUILD_EOF'
|
||||
#!/bin/bash
|
||||
# Rebuild Proxmark3 client and firmware with LED PWM control patch
|
||||
# Usage: ./rebuild-pm3.sh [--flash]
|
||||
|
||||
set -e
|
||||
|
||||
PM3_HOME="$HOME/.pm3/proxmark3"
|
||||
BUILD_DIR="/tmp/proxmark3-rebuild"
|
||||
PATCH_FILE="$PM3_HOME/patches/led-pwm-control.patch"
|
||||
|
||||
echo "=== Proxmark3 Rebuild Script ==="
|
||||
echo "This will rebuild the PM3 client and firmware with LED PWM control."
|
||||
echo ""
|
||||
|
||||
# Check for ARM toolchain
|
||||
if ! command -v arm-none-eabi-gcc &> /dev/null; then
|
||||
echo "ERROR: ARM toolchain not found. Install with:"
|
||||
echo " sudo apt install gcc-arm-none-eabi"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean previous build
|
||||
rm -rf "$BUILD_DIR"
|
||||
|
||||
# Clone fresh copy
|
||||
echo "Cloning Proxmark3 repository..."
|
||||
git clone --depth 1 https://github.com/RfidResearchGroup/proxmark3 "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Apply LED PWM control patch
|
||||
if [ -f "$PATCH_FILE" ]; then
|
||||
echo "Applying LED PWM control patch..."
|
||||
patch -p1 < "$PATCH_FILE"
|
||||
echo "Patch applied"
|
||||
else
|
||||
echo "WARNING: LED patch not found at $PATCH_FILE"
|
||||
fi
|
||||
|
||||
# Apply HF booster detection patch
|
||||
if [ -f "$PM3_HOME/patches/hf-booster-detection.patch" ]; then
|
||||
echo "Applying HF booster detection patch..."
|
||||
patch -p1 < "$PM3_HOME/patches/hf-booster-detection.patch"
|
||||
fi
|
||||
|
||||
# Add Dangerous Pi branding to version string
|
||||
echo "Adding Dangerous Pi branding..."
|
||||
sed -i 's/^fullgitinfo="Iceman"$/fullgitinfo="Iceman\/DangerousPi"/' tools/mkversion.sh
|
||||
|
||||
# Configure build
|
||||
echo "Configuring build..."
|
||||
cat > Makefile.platform << EOF
|
||||
PLATFORM=PM3GENERIC
|
||||
LED_ORDER=PM3EASY
|
||||
EOF
|
||||
|
||||
# Build firmware and client
|
||||
echo "Building firmware (this takes a while on Pi Zero)..."
|
||||
make clean
|
||||
make -j$(nproc)
|
||||
|
||||
# Build client with Python bindings
|
||||
echo "Building client..."
|
||||
cd client
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. -DBUILD_PYTHON_LIB=ON
|
||||
make -j$(nproc)
|
||||
|
||||
# Build experimental Python library
|
||||
echo "Building Python bindings..."
|
||||
cd ../experimental_lib
|
||||
./00make_swig.sh
|
||||
./01make_lib.sh
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Backup current installation
|
||||
echo "Backing up current installation..."
|
||||
if [ -f "$PM3_HOME/client/proxmark3" ]; then
|
||||
cp "$PM3_HOME/client/proxmark3" "$PM3_HOME/client/proxmark3.bak"
|
||||
fi
|
||||
if [ -f "$PM3_HOME/firmware/fullimage.elf" ]; then
|
||||
cp "$PM3_HOME/firmware/fullimage.elf" "$PM3_HOME/firmware/fullimage.elf.bak"
|
||||
fi
|
||||
|
||||
# Install new binaries
|
||||
echo "Installing new client..."
|
||||
cp "$BUILD_DIR/client/build/proxmark3" "$PM3_HOME/client/"
|
||||
cp "$BUILD_DIR/client/experimental_lib/build/libpm3rrg_rdv4.so" "$PM3_HOME/client/pyscripts/"
|
||||
cp "$BUILD_DIR/client/pyscripts/*.py" "$PM3_HOME/client/pyscripts/"
|
||||
|
||||
echo "Installing new firmware..."
|
||||
cp "$BUILD_DIR/bootrom/obj/bootrom.elf" "$PM3_HOME/firmware/"
|
||||
cp "$BUILD_DIR/armsrc/obj/fullimage.elf" "$PM3_HOME/firmware/"
|
||||
|
||||
# Update flash utilities
|
||||
echo "Updating flash utilities..."
|
||||
cp "$BUILD_DIR/pm3-flash-all" "$PM3_HOME/"
|
||||
cp "$BUILD_DIR/pm3-flash-bootrom" "$PM3_HOME/"
|
||||
cp "$BUILD_DIR/pm3-flash-fullimage" "$PM3_HOME/"
|
||||
chmod +x "$PM3_HOME/pm3-flash-"*
|
||||
|
||||
# Update version
|
||||
echo "Updating version info..."
|
||||
cd "$BUILD_DIR"
|
||||
git describe --always --tags > "$PM3_HOME/VERSION.txt"
|
||||
echo "Build date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> "$PM3_HOME/VERSION.txt"
|
||||
echo "Built with LED PWM control patch" >> "$PM3_HOME/VERSION.txt"
|
||||
|
||||
echo ""
|
||||
echo "=== Build Complete ==="
|
||||
echo "New client: $PM3_HOME/client/proxmark3"
|
||||
echo "New firmware: $PM3_HOME/firmware/"
|
||||
echo ""
|
||||
|
||||
# Flash if requested
|
||||
if [ "$1" == "--flash" ]; then
|
||||
echo "Flashing firmware to connected device..."
|
||||
cd "$PM3_HOME"
|
||||
./pm3-flash-all
|
||||
echo "Flash complete"
|
||||
else
|
||||
echo "To flash the new firmware, run:"
|
||||
echo " cd $PM3_HOME && ./pm3-flash-all"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$BUILD_DIR"
|
||||
echo "Cleanup complete"
|
||||
REBUILD_EOF
|
||||
chmod +x "$DEFAULT_HOME/.pm3/proxmark3/scripts/rebuild-pm3.sh"
|
||||
|
||||
# Set proper ownership
|
||||
echo "Setting ownership..."
|
||||
chown -R "$DEFAULT_USER:$DEFAULT_USER" "$DEFAULT_HOME/.pm3"
|
||||
|
||||
# Add Python path to environment
|
||||
echo "Configuring Python path..."
|
||||
touch "$DEFAULT_HOME/.bashrc"
|
||||
if ! grep -q "PYTHONPATH.*\.pm3" "$DEFAULT_HOME/.bashrc"; then
|
||||
echo 'export PYTHONPATH=$HOME/.pm3/proxmark3/client/pyscripts:$PYTHONPATH' >> "$DEFAULT_HOME/.bashrc"
|
||||
fi
|
||||
|
||||
# --- Verification ---
|
||||
echo "Verifying installation..."
|
||||
|
||||
ERRORS=0
|
||||
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/proxmark3" ]; then
|
||||
echo "Client executable installed"
|
||||
else
|
||||
echo "ERROR: Client executable not found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Verify library architecture
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/libpm3rrg_rdv4.so" ]; then
|
||||
LIB_ARCH=$(file "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/libpm3rrg_rdv4.so" | grep -o 'ARM aarch64\|x86-64\|ARM,')
|
||||
if [ "$LIB_ARCH" = "ARM aarch64" ]; then
|
||||
echo "Library architecture correct: $LIB_ARCH"
|
||||
else
|
||||
echo "ERROR: Library architecture mismatch! Expected ARM aarch64, got: $LIB_ARCH"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/pm3.py" ]; then
|
||||
echo "Python module installed"
|
||||
else
|
||||
echo "ERROR: Python module not found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/_pm3.so" ]; then
|
||||
echo "Python bindings library installed (_pm3.so)"
|
||||
else
|
||||
echo "ERROR: Python bindings library not found (_pm3.so)"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/firmware/fullimage.elf" ]; then
|
||||
echo "Firmware files installed"
|
||||
else
|
||||
echo "ERROR: Firmware files not found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/pm3-flash-all" ]; then
|
||||
echo "Flash utilities installed"
|
||||
else
|
||||
echo "WARNING: Flash utilities not found"
|
||||
fi
|
||||
|
||||
if [ $ERRORS -gt 0 ]; then
|
||||
echo "ERROR: $ERRORS verification checks failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up tarball
|
||||
rm -f /tmp/pm3-prebuilt.tar.gz
|
||||
|
||||
# Print summary
|
||||
echo "=== Proxmark3 installation complete ==="
|
||||
echo "Installation: $DEFAULT_HOME/.pm3/proxmark3/"
|
||||
echo "Client: $DEFAULT_HOME/.pm3/proxmark3/client/proxmark3"
|
||||
echo "Flash utils: $DEFAULT_HOME/.pm3/proxmark3/pm3-flash-all"
|
||||
echo "Python: $DEFAULT_HOME/.pm3/proxmark3/client/pyscripts/pm3.py"
|
||||
echo "Firmware: $DEFAULT_HOME/.pm3/proxmark3/firmware/"
|
||||
if [ -f "$DEFAULT_HOME/.pm3/proxmark3/COMPONENT_VERSION" ]; then
|
||||
echo "Version info:"
|
||||
cat "$DEFAULT_HOME/.pm3/proxmark3/COMPONENT_VERSION"
|
||||
fi
|
||||
93
pi-gen/stageDangerousPi/02-pm3-install/00-run.sh
Executable file
93
pi-gen/stageDangerousPi/02-pm3-install/00-run.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# Pre-chroot script: Source a pre-built PM3 tarball for installation.
|
||||
# This runs on the host before the chroot script.
|
||||
#
|
||||
# Tarball sources (checked in order):
|
||||
# 1. PM3_TARBALL env var (explicit path to a local tarball)
|
||||
# 2. Local file in this substage's files/ directory
|
||||
# 3. Download from GitHub Releases (dangerous-tacos/dangerous-pi)
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# --- Detect Python ABI in chroot ---
|
||||
PYTHON_VERSION=$(chroot "${ROOTFS_DIR}" python3 -c \
|
||||
'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || echo "3.12")
|
||||
PYTHON_ABI="cp$(echo "$PYTHON_VERSION" | tr -d '.')"
|
||||
echo "Detected Python ${PYTHON_VERSION} (ABI: ${PYTHON_ABI}) in chroot"
|
||||
|
||||
# --- Read PM3 version config ---
|
||||
PM3_COMMIT=""
|
||||
if [ -f "${SCRIPT_DIR}/pm3-version.conf" ]; then
|
||||
. "${SCRIPT_DIR}/pm3-version.conf"
|
||||
fi
|
||||
|
||||
# --- Locate tarball ---
|
||||
TARBALL=""
|
||||
|
||||
# 1. Explicit env var
|
||||
if [ -n "${PM3_TARBALL:-}" ] && [ -f "$PM3_TARBALL" ]; then
|
||||
echo "Using PM3 tarball from PM3_TARBALL: $PM3_TARBALL"
|
||||
TARBALL="$PM3_TARBALL"
|
||||
fi
|
||||
|
||||
# 2. Local file in files/ directory
|
||||
if [ -z "$TARBALL" ]; then
|
||||
LOCAL_MATCH=$(ls "${SCRIPT_DIR}"/files/pm3-*-aarch64-linux-${PYTHON_ABI}.tar.gz 2>/dev/null | head -1)
|
||||
if [ -n "$LOCAL_MATCH" ]; then
|
||||
echo "Using local PM3 tarball: $LOCAL_MATCH"
|
||||
TARBALL="$LOCAL_MATCH"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Download from GitHub Releases
|
||||
if [ -z "$TARBALL" ]; then
|
||||
GH_REPO="dangerous-tacos/dangerous-pi"
|
||||
echo "Downloading PM3 tarball from GitHub Releases (${GH_REPO})..."
|
||||
|
||||
# Determine which release to fetch
|
||||
if [ -n "$PM3_COMMIT" ]; then
|
||||
# Try to find a release matching the commit
|
||||
RELEASE_URL="https://api.github.com/repos/${GH_REPO}/releases/latest"
|
||||
else
|
||||
RELEASE_URL="https://api.github.com/repos/${GH_REPO}/releases/latest"
|
||||
fi
|
||||
|
||||
# Get asset download URL for the matching ABI
|
||||
ASSET_PATTERN="pm3-.*-aarch64-linux-${PYTHON_ABI}\\.tar\\.gz"
|
||||
DOWNLOAD_URL=$(curl -sL "$RELEASE_URL" | \
|
||||
grep -oP "\"browser_download_url\":\\s*\"\\K[^\"]*${ASSET_PATTERN}" | head -1)
|
||||
|
||||
if [ -n "$DOWNLOAD_URL" ]; then
|
||||
TARBALL="/tmp/pm3-prebuilt-download.tar.gz"
|
||||
echo "Downloading: $DOWNLOAD_URL"
|
||||
curl -sL -o "$TARBALL" "$DOWNLOAD_URL"
|
||||
echo "Downloaded PM3 tarball ($(du -h "$TARBALL" | cut -f1))"
|
||||
else
|
||||
echo "WARNING: Could not find PM3 tarball for ABI ${PYTHON_ABI} in latest release"
|
||||
echo "Falling back to compile-from-source (this will take 45-60 min under QEMU)"
|
||||
echo "To avoid this, set PM3_TARBALL=/path/to/pm3-*.tar.gz"
|
||||
|
||||
# Copy patches and version config for the compile fallback
|
||||
if [ -f "${SCRIPT_DIR}/led-pwm-control.patch" ]; then
|
||||
cp "${SCRIPT_DIR}/led-pwm-control.patch" "${ROOTFS_DIR}/tmp/"
|
||||
fi
|
||||
if [ -f "${SCRIPT_DIR}/hf-booster-detection.patch" ]; then
|
||||
cp "${SCRIPT_DIR}/hf-booster-detection.patch" "${ROOTFS_DIR}/tmp/"
|
||||
fi
|
||||
if [ -f "${SCRIPT_DIR}/pm3-version.conf" ]; then
|
||||
cp "${SCRIPT_DIR}/pm3-version.conf" "${ROOTFS_DIR}/tmp/"
|
||||
fi
|
||||
touch "${ROOTFS_DIR}/tmp/PM3_COMPILE_FROM_SOURCE"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Copy tarball into rootfs ---
|
||||
cp "$TARBALL" "${ROOTFS_DIR}/tmp/pm3-prebuilt.tar.gz"
|
||||
echo "PM3 tarball staged at /tmp/pm3-prebuilt.tar.gz in rootfs"
|
||||
|
||||
# Clean up downloaded temp file
|
||||
if [ "${TARBALL}" = "/tmp/pm3-prebuilt-download.tar.gz" ]; then
|
||||
rm -f "$TARBALL"
|
||||
fi
|
||||
@@ -0,0 +1,86 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dangerous Pi <dangerous-pi@users.noreply.github.com>
|
||||
Date: Tue, 11 Feb 2026 00:00:00 +0000
|
||||
Subject: [PATCH] client: detect booster board / LC tank loading during hw tune
|
||||
|
||||
When a booster board or other LC tank circuit is installed on a PM3
|
||||
Easy (non-RDV4), the HF antenna voltage during `hw tune` drops into
|
||||
the 2550-2750 mV range. Previously this was reported as "unusable"
|
||||
with no Q-factor calculation. This change detects the loaded state
|
||||
and warns the user about the likely cause.
|
||||
|
||||
The detection only fires on non-RDV4 devices since the voltage range
|
||||
is calibrated for the PM3 Easy voltage divider (11:1, vdd_other=5400).
|
||||
On RDV4 (42.67:1 divider), the same mV reading has different meaning.
|
||||
---
|
||||
client/src/cmdhw.c | 27 ++++++++++++++++++++++-----
|
||||
1 file changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c
|
||||
--- a/client/src/cmdhw.c
|
||||
+++ b/client/src/cmdhw.c
|
||||
@@ -909,6 +909,8 @@
|
||||
#define LF_MARGINAL_V 10000
|
||||
#define HF_UNUSABLE_V 3000
|
||||
#define HF_MARGINAL_V 5000
|
||||
+#define HF_BOOSTER_LOW 2550 // lower bound of HF booster/LC tank loading range (mV)
|
||||
+#define HF_BOOSTER_HIGH 2750 // upper bound of HF booster/LC tank loading range (mV)
|
||||
#define ANTENNA_ERROR 1.00 // current algo has 3% error margin.
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
@@ -1055,6 +1057,10 @@
|
||||
|
||||
memset(judgement, 0, sizeof(judgement));
|
||||
|
||||
+ bool hf_booster_detected = (package->v_hf >= HF_BOOSTER_LOW
|
||||
+ && package->v_hf <= HF_BOOSTER_HIGH
|
||||
+ && !IfPm3Rdv4Fw());
|
||||
+
|
||||
PrintAndLogEx(SUCCESS, "");
|
||||
PrintAndLogEx(SUCCESS, "Approx. Q factor measurement");
|
||||
|
||||
@@ -1062,16 +1068,24 @@
|
||||
// Q measure with Vlr=Q*(2*Vdd/pi)
|
||||
double hfq = (double)package->v_hf * 3.14 / 2 / vdd;
|
||||
PrintAndLogEx(SUCCESS, "Peak voltage.......... " _YELLOW_("%.1lf"), hfq);
|
||||
- }
|
||||
-
|
||||
- if (package->v_hf < HF_UNUSABLE_V)
|
||||
+ } else if (hf_booster_detected) {
|
||||
+ PrintAndLogEx(SUCCESS, "Your HF antenna measurement shows");
|
||||
+ PrintAndLogEx(SUCCESS, "low voltage that is consistent");
|
||||
+ PrintAndLogEx(SUCCESS, "with the installation of a booster");
|
||||
+ PrintAndLogEx(SUCCESS, "board. If you do not have a");
|
||||
+ PrintAndLogEx(SUCCESS, "booster board installed, either");
|
||||
+ PrintAndLogEx(SUCCESS, "your antenna is malfunctioning or");
|
||||
+ PrintAndLogEx(SUCCESS, "you have a tag on the HF antenna.");
|
||||
+ }
|
||||
+
|
||||
+ if (hf_booster_detected)
|
||||
+ snprintf(judgement, sizeof(judgement), _YELLOW_("loaded"));
|
||||
+ else if (package->v_hf < HF_UNUSABLE_V)
|
||||
snprintf(judgement, sizeof(judgement), _RED_("unusable"));
|
||||
else if (package->v_hf < HF_MARGINAL_V)
|
||||
snprintf(judgement, sizeof(judgement), _YELLOW_("marginal"));
|
||||
else
|
||||
snprintf(judgement, sizeof(judgement), _GREEN_("ok"));
|
||||
|
||||
- PrintAndLogEx((package->v_hf < HF_UNUSABLE_V) ? WARNING : SUCCESS, "HF antenna ( %s )", judgement);
|
||||
+ PrintAndLogEx((package->v_hf < HF_UNUSABLE_V && !hf_booster_detected) ? WARNING : SUCCESS, "HF antenna ( %s )", judgement);
|
||||
+
|
||||
+ if (hf_booster_detected) {
|
||||
+ PrintAndLogEx(NORMAL, "");
|
||||
+ }
|
||||
|
||||
// graph LF measurements
|
||||
// even here, these values has 3% error.
|
||||
@@ -1103,6 +1117,9 @@
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Q factor must be measured without tag on the antenna");
|
||||
+ if (hf_booster_detected) {
|
||||
+ PrintAndLogEx(INFO, "Booster board detection range: %.2f - %.2f V", HF_BOOSTER_LOW / 1000.0, HF_BOOSTER_HIGH / 1000.0);
|
||||
+ }
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
747
pi-gen/stageDangerousPi/02-pm3-install/led-pwm-control.patch
Normal file
747
pi-gen/stageDangerousPi/02-pm3-install/led-pwm-control.patch
Normal file
@@ -0,0 +1,747 @@
|
||||
diff --git a/armsrc/appmain.c b/armsrc/appmain.c
|
||||
index 88ce070..cbeb7d2 100644
|
||||
--- a/armsrc/appmain.c
|
||||
+++ b/armsrc/appmain.c
|
||||
@@ -921,6 +921,100 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
+ case CMD_LED_CONTROL: {
|
||||
+ payload_led_control_t *led_data = (payload_led_control_t *)packet->data.asBytes;
|
||||
+
|
||||
+ // Check for extended struct (8 bytes) vs legacy (3 bytes)
|
||||
+ bool extended = (packet->length >= 8);
|
||||
+ uint16_t speed_ms = extended ? led_data->speed_ms : 500;
|
||||
+ uint16_t count = extended ? led_data->count : 5;
|
||||
+
|
||||
+ if (led_data->action == 0) {
|
||||
+ // Turn off
|
||||
+ if (led_data->led & LED_A) {
|
||||
+ led_pwm_disable(LED_A);
|
||||
+ LED_A_OFF();
|
||||
+ }
|
||||
+ if (led_data->led & LED_B) {
|
||||
+ led_pwm_disable(LED_B);
|
||||
+ LED_B_OFF();
|
||||
+ }
|
||||
+ if (led_data->led & LED_C) LED_C_OFF();
|
||||
+ if (led_data->led & LED_D) LED_D_OFF();
|
||||
+
|
||||
+ } else if (led_data->action == 1) {
|
||||
+ // Turn on
|
||||
+ if (led_data->led & LED_A) {
|
||||
+ led_pwm_disable(LED_A);
|
||||
+ LED_A_ON();
|
||||
+ }
|
||||
+ if (led_data->led & LED_B) {
|
||||
+ led_pwm_disable(LED_B);
|
||||
+ LED_B_ON();
|
||||
+ }
|
||||
+ if (led_data->led & LED_C) LED_C_ON();
|
||||
+ if (led_data->led & LED_D) LED_D_ON();
|
||||
+
|
||||
+ } else if (led_data->action == 2) {
|
||||
+ // Toggle
|
||||
+ if (led_data->led & LED_A) {
|
||||
+ led_pwm_disable(LED_A);
|
||||
+ LED_A_INV();
|
||||
+ }
|
||||
+ if (led_data->led & LED_B) {
|
||||
+ led_pwm_disable(LED_B);
|
||||
+ LED_B_INV();
|
||||
+ }
|
||||
+ if (led_data->led & LED_C) LED_C_INV();
|
||||
+ if (led_data->led & LED_D) LED_D_INV();
|
||||
+
|
||||
+ } else if (led_data->action == 3) {
|
||||
+ // PWM brightness control
|
||||
+ if ((led_data->led & LED_A) && !(led_data->led & ~LED_A)) {
|
||||
+ // Only LED_A selected
|
||||
+ led_set_pwm_brightness(LED_A, led_data->brightness);
|
||||
+ } else if ((led_data->led & LED_B) && !(led_data->led & ~LED_B)) {
|
||||
+ // Only LED_B selected
|
||||
+ led_set_pwm_brightness(LED_B, led_data->brightness);
|
||||
+ } else if ((led_data->led & LED_A) && (led_data->led & LED_B) && !(led_data->led & ~(LED_A | LED_B))) {
|
||||
+ // Both LED_A and LED_B selected
|
||||
+ led_set_pwm_brightness(LED_A, led_data->brightness);
|
||||
+ led_set_pwm_brightness(LED_B, led_data->brightness);
|
||||
+ } else {
|
||||
+ // PWM only supported for LED_A and LED_B
|
||||
+ reply_ng(CMD_LED_CONTROL, PM3_EINVARG, NULL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ } else if (led_data->action == 4) {
|
||||
+ // PULSE effect (PWM LEDs only)
|
||||
+ if (led_data->led & ~(LED_A | LED_B)) {
|
||||
+ reply_ng(CMD_LED_CONTROL, PM3_EINVARG, NULL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+ led_effect_pulse(led_data->led, speed_ms, count);
|
||||
+
|
||||
+ } else if (led_data->action == 5) {
|
||||
+ // FADE effect (PWM LEDs only)
|
||||
+ if (led_data->led & ~(LED_A | LED_B)) {
|
||||
+ reply_ng(CMD_LED_CONTROL, PM3_EINVARG, NULL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+ led_effect_fade(led_data->led, speed_ms);
|
||||
+
|
||||
+ } else if (led_data->action == 6) {
|
||||
+ // BLINK effect (all LEDs supported)
|
||||
+ led_effect_blink(led_data->led, speed_ms, count);
|
||||
+
|
||||
+ } else {
|
||||
+ // Unknown action
|
||||
+ reply_ng(CMD_LED_CONTROL, PM3_EINVARG, NULL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ reply_ng(CMD_LED_CONTROL, PM3_SUCCESS, NULL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
// always available
|
||||
case CMD_HF_DROPFIELD: {
|
||||
hf_field_off();
|
||||
diff --git a/armsrc/util.c b/armsrc/util.c
|
||||
index 0df8935..6d8246f 100644
|
||||
--- a/armsrc/util.c
|
||||
+++ b/armsrc/util.c
|
||||
@@ -251,17 +251,17 @@ int BUTTON_CLICKED(int ms) {
|
||||
return BUTTON_NO_CLICK;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
- AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(1);
|
||||
// 48 MHz / 1024 gives 46.875 kHz
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CDTYR = 0;
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CPRDR = 0xffff;
|
||||
|
||||
- uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t start = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
int letoff = 0;
|
||||
for (;;) {
|
||||
- uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t now = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
// We haven't let off the button yet
|
||||
if (!letoff) {
|
||||
@@ -270,7 +270,7 @@ int BUTTON_CLICKED(int ms) {
|
||||
letoff = 1;
|
||||
|
||||
// reset our timer for 500ms
|
||||
- start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ start = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
ticks = ((MCK / 1000) * (500)) >> 10;
|
||||
}
|
||||
|
||||
@@ -316,16 +316,16 @@ int BUTTON_HELD(int ms) {
|
||||
}
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
- AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(1);
|
||||
// 48 MHz / 1024 gives 46.875 kHz
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CDTYR = 0;
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CPRDR = 0xffff;
|
||||
|
||||
- uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t start = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
for (;;) {
|
||||
- uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t now = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
// As soon as our button let go, we didn't hold long enough
|
||||
if (BUTTON_PRESS() == false) {
|
||||
@@ -415,3 +415,241 @@ void convertToHexArray(uint32_t num, uint8_t *partialkey) {
|
||||
partialkey[i] = (uint8_t)strtoul(group, NULL, 2);
|
||||
}
|
||||
}
|
||||
+
|
||||
+// PWM LED brightness control
|
||||
+#define LED_PWM_PERIOD 1000 // 48kHz PWM frequency (48MHz / 1000)
|
||||
+
|
||||
+static bool pwm0_initialized = false;
|
||||
+static bool pwm2_initialized = false;
|
||||
+
|
||||
+void led_set_pwm_brightness(uint8_t led, uint8_t brightness) {
|
||||
+ // brightness: 0-100
|
||||
+ if (brightness > 100) {
|
||||
+ brightness = 100;
|
||||
+ }
|
||||
+
|
||||
+ // Convert 0-100 to 0-1000 duty cycle
|
||||
+ uint16_t duty = (brightness * LED_PWM_PERIOD) / 100;
|
||||
+
|
||||
+ // Inverted duty cycle for active-low LEDs
|
||||
+ uint16_t inverted_duty = LED_PWM_PERIOD - duty;
|
||||
+
|
||||
+ if (led == LED_A) {
|
||||
+ // LED_A uses PWM Channel 0
|
||||
+ if (!pwm0_initialized) {
|
||||
+ // Enable PWM clock
|
||||
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PWMC);
|
||||
+
|
||||
+ // Configure PA0 as PWM0 peripheral function
|
||||
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_LED_A; // Disable GPIO control
|
||||
+ AT91C_BASE_PIOA->PIO_ASR = GPIO_LED_A; // Select peripheral A (PWM)
|
||||
+
|
||||
+ // Configure PWM Channel 0
|
||||
+ AT91C_BASE_PWMC_CH0->PWMC_CMR = AT91C_PWMC_CPRE_MCK; // Clock = MCK
|
||||
+ AT91C_BASE_PWMC_CH0->PWMC_CPRDR = LED_PWM_PERIOD; // Period
|
||||
+
|
||||
+ // Enable PWM Channel 0
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+
|
||||
+ pwm0_initialized = true;
|
||||
+ }
|
||||
+
|
||||
+ // Update duty cycle
|
||||
+ AT91C_BASE_PWMC_CH0->PWMC_CUPDR = inverted_duty;
|
||||
+
|
||||
+ } else if (led == LED_B) {
|
||||
+ // LED_B uses PWM Channel 2
|
||||
+ if (!pwm2_initialized) {
|
||||
+ // Enable PWM clock
|
||||
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PWMC);
|
||||
+
|
||||
+ // Configure PA2 as PWM2 peripheral function
|
||||
+ AT91C_BASE_PIOA->PIO_PDR = GPIO_LED_B; // Disable GPIO control
|
||||
+ AT91C_BASE_PIOA->PIO_ASR = GPIO_LED_B; // Select peripheral A (PWM)
|
||||
+
|
||||
+ // Configure PWM Channel 2
|
||||
+ AT91C_BASE_PWMC_CH2->PWMC_CMR = AT91C_PWMC_CPRE_MCK; // Clock = MCK
|
||||
+ AT91C_BASE_PWMC_CH2->PWMC_CPRDR = LED_PWM_PERIOD; // Period
|
||||
+
|
||||
+ // Enable PWM Channel 2
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(2);
|
||||
+
|
||||
+ pwm2_initialized = true;
|
||||
+ }
|
||||
+
|
||||
+ // Update duty cycle
|
||||
+ AT91C_BASE_PWMC_CH2->PWMC_CUPDR = inverted_duty;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void led_pwm_disable(uint8_t led) {
|
||||
+ if (led == LED_A && pwm0_initialized) {
|
||||
+ // Disable PWM Channel 0
|
||||
+ AT91C_BASE_PWMC->PWMC_DIS = PWM_CHANNEL(0);
|
||||
+
|
||||
+ // Return PA0 to GPIO control
|
||||
+ AT91C_BASE_PIOA->PIO_PER = GPIO_LED_A;
|
||||
+
|
||||
+ pwm0_initialized = false;
|
||||
+
|
||||
+ } else if (led == LED_B && pwm2_initialized) {
|
||||
+ // Disable PWM Channel 2
|
||||
+ AT91C_BASE_PWMC->PWMC_DIS = PWM_CHANNEL(2);
|
||||
+
|
||||
+ // Return PA2 to GPIO control
|
||||
+ AT91C_BASE_PIOA->PIO_PER = GPIO_LED_B;
|
||||
+
|
||||
+ pwm2_initialized = false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// ============================================================================
|
||||
+// LED Effect Functions (firmware-side animations)
|
||||
+// ============================================================================
|
||||
+
|
||||
+static volatile bool led_effect_stop_requested = false;
|
||||
+
|
||||
+void led_effects_stop(void) {
|
||||
+ led_effect_stop_requested = true;
|
||||
+}
|
||||
+
|
||||
+// Check if effect should stop (button press, USB data, or stop flag)
|
||||
+static bool should_stop_effect(void) {
|
||||
+ WDT_HIT();
|
||||
+ return led_effect_stop_requested || BUTTON_PRESS() || data_available();
|
||||
+}
|
||||
+
|
||||
+// PULSE: Fade in and out continuously (PWM LEDs only: A, B)
|
||||
+void led_effect_pulse(uint8_t led_mask, uint16_t speed_ms, uint16_t count) {
|
||||
+ led_effect_stop_requested = false;
|
||||
+
|
||||
+ // Only LED_A and LED_B support PWM
|
||||
+ uint8_t pwm_mask = led_mask & (LED_A | LED_B);
|
||||
+ if (pwm_mask == 0) return;
|
||||
+
|
||||
+ // Default speed if 0
|
||||
+ if (speed_ms == 0) speed_ms = 500;
|
||||
+
|
||||
+ // Calculate steps: 10ms per step, speed_ms/2 per half-cycle
|
||||
+ uint16_t step_delay = 10;
|
||||
+ uint16_t steps = speed_ms / step_delay / 2;
|
||||
+ if (steps < 1) steps = 1;
|
||||
+ if (steps > 50) steps = 50;
|
||||
+
|
||||
+ uint16_t cycles_done = 0;
|
||||
+ bool infinite = (count == 0);
|
||||
+
|
||||
+ while (infinite || cycles_done < count) {
|
||||
+ // Fade in (0 -> 100)
|
||||
+ for (uint16_t i = 0; i <= steps; i++) {
|
||||
+ if (should_stop_effect()) goto pulse_cleanup;
|
||||
+ uint8_t brightness = (i * 100) / steps;
|
||||
+ if (pwm_mask & LED_A) led_set_pwm_brightness(LED_A, brightness);
|
||||
+ if (pwm_mask & LED_B) led_set_pwm_brightness(LED_B, brightness);
|
||||
+ SpinDelay(step_delay);
|
||||
+ }
|
||||
+
|
||||
+ // Fade out (100 -> 0)
|
||||
+ for (uint16_t i = steps; i > 0; i--) {
|
||||
+ if (should_stop_effect()) goto pulse_cleanup;
|
||||
+ uint8_t brightness = (i * 100) / steps;
|
||||
+ if (pwm_mask & LED_A) led_set_pwm_brightness(LED_A, brightness);
|
||||
+ if (pwm_mask & LED_B) led_set_pwm_brightness(LED_B, brightness);
|
||||
+ SpinDelay(step_delay);
|
||||
+ }
|
||||
+
|
||||
+ cycles_done++;
|
||||
+ }
|
||||
+
|
||||
+pulse_cleanup:
|
||||
+ // Disable PWM and turn off LEDs
|
||||
+ if (pwm_mask & LED_A) { led_pwm_disable(LED_A); LED_A_OFF(); }
|
||||
+ if (pwm_mask & LED_B) { led_pwm_disable(LED_B); LED_B_OFF(); }
|
||||
+ led_effect_stop_requested = false;
|
||||
+}
|
||||
+
|
||||
+// FADE: Full brightness then fade out once (PWM LEDs only: A, B)
|
||||
+void led_effect_fade(uint8_t led_mask, uint16_t speed_ms) {
|
||||
+ led_effect_stop_requested = false;
|
||||
+
|
||||
+ uint8_t pwm_mask = led_mask & (LED_A | LED_B);
|
||||
+ if (pwm_mask == 0) return;
|
||||
+
|
||||
+ if (speed_ms == 0) speed_ms = 500;
|
||||
+
|
||||
+ uint16_t step_delay = 10;
|
||||
+ uint16_t steps = speed_ms / step_delay;
|
||||
+ if (steps < 1) steps = 1;
|
||||
+ if (steps > 100) steps = 100;
|
||||
+
|
||||
+ // Start at full brightness
|
||||
+ if (pwm_mask & LED_A) led_set_pwm_brightness(LED_A, 100);
|
||||
+ if (pwm_mask & LED_B) led_set_pwm_brightness(LED_B, 100);
|
||||
+
|
||||
+ // Fade out
|
||||
+ for (uint16_t i = steps; i > 0; i--) {
|
||||
+ if (should_stop_effect()) goto fade_cleanup;
|
||||
+ uint8_t brightness = (i * 100) / steps;
|
||||
+ if (pwm_mask & LED_A) led_set_pwm_brightness(LED_A, brightness);
|
||||
+ if (pwm_mask & LED_B) led_set_pwm_brightness(LED_B, brightness);
|
||||
+ SpinDelay(step_delay);
|
||||
+ }
|
||||
+
|
||||
+fade_cleanup:
|
||||
+ if (pwm_mask & LED_A) { led_pwm_disable(LED_A); LED_A_OFF(); }
|
||||
+ if (pwm_mask & LED_B) { led_pwm_disable(LED_B); LED_B_OFF(); }
|
||||
+ led_effect_stop_requested = false;
|
||||
+}
|
||||
+
|
||||
+// BLINK: Alternating on/off (works with ALL LEDs including C, D)
|
||||
+void led_effect_blink(uint8_t led_mask, uint16_t speed_ms, uint16_t count) {
|
||||
+ led_effect_stop_requested = false;
|
||||
+
|
||||
+ if (led_mask == 0) return;
|
||||
+ if (speed_ms == 0) speed_ms = 500;
|
||||
+
|
||||
+ // Disable any PWM first (use GPIO toggling)
|
||||
+ if (led_mask & LED_A) led_pwm_disable(LED_A);
|
||||
+ if (led_mask & LED_B) led_pwm_disable(LED_B);
|
||||
+
|
||||
+ uint16_t half_cycle = speed_ms / 2;
|
||||
+ if (half_cycle > 1390) half_cycle = 1390; // SpinDelay limit
|
||||
+
|
||||
+ uint16_t cycles_done = 0;
|
||||
+ bool infinite = (count == 0);
|
||||
+
|
||||
+ // Start with LEDs off
|
||||
+ if (led_mask & LED_A) LED_A_OFF();
|
||||
+ if (led_mask & LED_B) LED_B_OFF();
|
||||
+ if (led_mask & LED_C) LED_C_OFF();
|
||||
+ if (led_mask & LED_D) LED_D_OFF();
|
||||
+
|
||||
+ while (infinite || cycles_done < count) {
|
||||
+ if (should_stop_effect()) break;
|
||||
+
|
||||
+ // Toggle on
|
||||
+ if (led_mask & LED_A) LED_A_ON();
|
||||
+ if (led_mask & LED_B) LED_B_ON();
|
||||
+ if (led_mask & LED_C) LED_C_ON();
|
||||
+ if (led_mask & LED_D) LED_D_ON();
|
||||
+
|
||||
+ SpinDelay(half_cycle);
|
||||
+ if (should_stop_effect()) break;
|
||||
+
|
||||
+ // Toggle off
|
||||
+ if (led_mask & LED_A) LED_A_OFF();
|
||||
+ if (led_mask & LED_B) LED_B_OFF();
|
||||
+ if (led_mask & LED_C) LED_C_OFF();
|
||||
+ if (led_mask & LED_D) LED_D_OFF();
|
||||
+
|
||||
+ SpinDelay(half_cycle);
|
||||
+ cycles_done++;
|
||||
+ }
|
||||
+
|
||||
+ // Ensure LEDs are off when done
|
||||
+ if (led_mask & LED_A) LED_A_OFF();
|
||||
+ if (led_mask & LED_B) LED_B_OFF();
|
||||
+ if (led_mask & LED_C) LED_C_OFF();
|
||||
+ if (led_mask & LED_D) LED_D_OFF();
|
||||
+ led_effect_stop_requested = false;
|
||||
+}
|
||||
diff --git a/armsrc/util.h b/armsrc/util.h
|
||||
index fd99ac7..d558dda 100644
|
||||
--- a/armsrc/util.h
|
||||
+++ b/armsrc/util.h
|
||||
@@ -105,4 +105,13 @@ bool data_available_fast(void);
|
||||
uint32_t flash_size_from_cidr(uint32_t cidr);
|
||||
uint32_t get_flash_size(void);
|
||||
|
||||
+void led_set_pwm_brightness(uint8_t led, uint8_t brightness);
|
||||
+void led_pwm_disable(uint8_t led);
|
||||
+
|
||||
+// LED effect functions (firmware-side animations)
|
||||
+void led_effect_pulse(uint8_t led_mask, uint16_t speed_ms, uint16_t count);
|
||||
+void led_effect_fade(uint8_t led_mask, uint16_t speed_ms);
|
||||
+void led_effect_blink(uint8_t led_mask, uint16_t speed_ms, uint16_t count);
|
||||
+void led_effects_stop(void);
|
||||
+
|
||||
#endif
|
||||
diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c
|
||||
index 9bbdc98..ad877b0 100644
|
||||
--- a/client/src/cmdhw.c
|
||||
+++ b/client/src/cmdhw.c
|
||||
@@ -1504,6 +1504,193 @@ int set_fpga_mode(uint8_t mode) {
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
+static int CmdLed(const char *Cmd) {
|
||||
+ CLIParserContext *ctx;
|
||||
+ CLIParserInit(&ctx, "hw led",
|
||||
+ "Control Proxmark3 LEDs with optional PWM brightness and effects.\n"
|
||||
+ "LED A (green) and B (blue) support PWM effects (pulse, fade, brightness).\n"
|
||||
+ "All LEDs support blink effect.",
|
||||
+ "hw led --led a --on --> Turn on LED A\n"
|
||||
+ "hw led --led b --off --> Turn off LED B\n"
|
||||
+ "hw led --led a,b --toggle --> Toggle LEDs A and B\n"
|
||||
+ "hw led --led a --brightness 50 --> Set LED A to 50%% brightness (PWM)\n"
|
||||
+ "hw led --led a --pulse --> Pulse LED A (5 cycles, 500ms)\n"
|
||||
+ "hw led --led a --pulse --count 10 --speed 300 --> Pulse 10 times, 300ms cycle\n"
|
||||
+ "hw led --led b --fade --> Fade LED B out once\n"
|
||||
+ "hw led --led a,b,c,d --blink --> Blink all LEDs\n"
|
||||
+ "hw led --led c,d --blink --count 20 --speed 200 --> Fast blink non-PWM LEDs");
|
||||
+
|
||||
+ void *argtable[] = {
|
||||
+ arg_param_begin,
|
||||
+ arg_str1(NULL, "led", "<a|b|c|d|all>", "LED selection (comma separated)"),
|
||||
+ arg_lit0(NULL, "on", "Turn LED on"),
|
||||
+ arg_lit0(NULL, "off", "Turn LED off"),
|
||||
+ arg_lit0(NULL, "toggle", "Toggle LED"),
|
||||
+ arg_int0(NULL, "brightness", "<0-100>", "LED brightness percentage (PWM, LED A and B only)"),
|
||||
+ arg_lit0(NULL, "pulse", "Pulse effect - fade in/out (PWM LEDs only)"),
|
||||
+ arg_lit0(NULL, "fade", "Fade effect - fade out from full (PWM LEDs only)"),
|
||||
+ arg_lit0(NULL, "blink", "Blink effect - on/off alternating (all LEDs)"),
|
||||
+ arg_int0(NULL, "speed", "<ms>", "Effect cycle time in milliseconds (default 500)"),
|
||||
+ arg_int0(NULL, "count", "<n>", "Number of effect cycles (default 5, 0=infinite)"),
|
||||
+ arg_param_end
|
||||
+ };
|
||||
+ CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
+
|
||||
+ int led_len = 63;
|
||||
+ char led_str[64] = {0};
|
||||
+ CLIGetStrWithReturn(ctx, 1, (uint8_t *)led_str, &led_len);
|
||||
+ bool on = arg_get_lit(ctx, 2);
|
||||
+ bool off = arg_get_lit(ctx, 3);
|
||||
+ bool toggle = arg_get_lit(ctx, 4);
|
||||
+ int brightness = arg_get_int_def(ctx, 5, -1);
|
||||
+ bool pulse = arg_get_lit(ctx, 6);
|
||||
+ bool fade = arg_get_lit(ctx, 7);
|
||||
+ bool blink = arg_get_lit(ctx, 8);
|
||||
+ int speed = arg_get_int_def(ctx, 9, 500);
|
||||
+ int count = arg_get_int_def(ctx, 10, 5);
|
||||
+ CLIParserFree(ctx);
|
||||
+
|
||||
+ // Count how many actions specified
|
||||
+ int action_count = on + off + toggle + (brightness >= 0) + pulse + fade + blink;
|
||||
+ if (action_count != 1) {
|
||||
+ PrintAndLogEx(ERR, "Specify exactly one action: --on, --off, --toggle, --brightness, --pulse, --fade, or --blink");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Parse LED selection
|
||||
+ uint8_t led_mask = 0;
|
||||
+ char *token = strtok(led_str, ",");
|
||||
+ while (token != NULL) {
|
||||
+ // Trim leading whitespace
|
||||
+ while (*token == ' ') token++;
|
||||
+
|
||||
+ if (strcasecmp(token, "a") == 0) {
|
||||
+ led_mask |= 1; // LED_A
|
||||
+ } else if (strcasecmp(token, "b") == 0) {
|
||||
+ led_mask |= 2; // LED_B
|
||||
+ } else if (strcasecmp(token, "c") == 0) {
|
||||
+ led_mask |= 4; // LED_C
|
||||
+ } else if (strcasecmp(token, "d") == 0) {
|
||||
+ led_mask |= 8; // LED_D
|
||||
+ } else if (strcasecmp(token, "all") == 0) {
|
||||
+ led_mask = 15; // All LEDs
|
||||
+ } else {
|
||||
+ PrintAndLogEx(ERR, "Invalid LED: '%s' (use a, b, c, d, or all)", token);
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+ token = strtok(NULL, ",");
|
||||
+ }
|
||||
+
|
||||
+ if (led_mask == 0) {
|
||||
+ PrintAndLogEx(ERR, "No LEDs selected");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Validate PWM-only actions (brightness, pulse, fade)
|
||||
+ if ((brightness >= 0 || pulse || fade) && (led_mask & ~0x03)) {
|
||||
+ PrintAndLogEx(ERR, "PWM effects (pulse, fade, brightness) only supported for LED A and B");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Validate brightness range
|
||||
+ if (brightness > 100) {
|
||||
+ PrintAndLogEx(ERR, "Brightness must be 0-100");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Validate speed range
|
||||
+ if (speed < 50 || speed > 10000) {
|
||||
+ PrintAndLogEx(ERR, "Speed must be between 50 and 10000 ms");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Validate count
|
||||
+ if (count < 0 || count > 65535) {
|
||||
+ PrintAndLogEx(ERR, "Count must be 0-65535 (0 = infinite)");
|
||||
+ return PM3_EINVARG;
|
||||
+ }
|
||||
+
|
||||
+ // Build extended payload (8 bytes)
|
||||
+ struct {
|
||||
+ uint8_t led;
|
||||
+ uint8_t action;
|
||||
+ uint8_t brightness;
|
||||
+ uint8_t reserved;
|
||||
+ uint16_t speed_ms;
|
||||
+ uint16_t count;
|
||||
+ } PACKED payload;
|
||||
+
|
||||
+ payload.led = led_mask;
|
||||
+ payload.brightness = (brightness >= 0) ? brightness : 100;
|
||||
+ payload.reserved = 0;
|
||||
+ payload.speed_ms = speed;
|
||||
+ payload.count = count;
|
||||
+
|
||||
+ // Determine action code
|
||||
+ if (off) {
|
||||
+ payload.action = 0;
|
||||
+ } else if (on) {
|
||||
+ payload.action = 1;
|
||||
+ } else if (toggle) {
|
||||
+ payload.action = 2;
|
||||
+ } else if (brightness >= 0) {
|
||||
+ payload.action = 3;
|
||||
+ } else if (pulse) {
|
||||
+ payload.action = 4;
|
||||
+ } else if (fade) {
|
||||
+ payload.action = 5;
|
||||
+ } else if (blink) {
|
||||
+ payload.action = 6;
|
||||
+ }
|
||||
+
|
||||
+ // Print feedback for effects
|
||||
+ if (pulse || fade || blink) {
|
||||
+ const char *effect_name = pulse ? "pulse" : (fade ? "fade" : "blink");
|
||||
+ PrintAndLogEx(INFO, "LED %s: LEDs=%s%s%s%s, speed=%dms, count=%d",
|
||||
+ effect_name,
|
||||
+ (led_mask & 1) ? "A" : "",
|
||||
+ (led_mask & 2) ? "B" : "",
|
||||
+ (led_mask & 4) ? "C" : "",
|
||||
+ (led_mask & 8) ? "D" : "",
|
||||
+ payload.speed_ms,
|
||||
+ payload.count);
|
||||
+
|
||||
+ if (count == 0) {
|
||||
+ PrintAndLogEx(INFO, "Running indefinitely. Press button on device or send any command to stop.");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ clearCommandBuffer();
|
||||
+ SendCommandNG(CMD_LED_CONTROL, (uint8_t *)&payload, sizeof(payload));
|
||||
+
|
||||
+ // Calculate timeout based on effect duration
|
||||
+ uint32_t timeout = 2000;
|
||||
+ if (pulse || blink) {
|
||||
+ if (count == 0) {
|
||||
+ timeout = 0; // No wait for infinite effects
|
||||
+ } else {
|
||||
+ timeout = (count * speed) + 2000;
|
||||
+ if (timeout > 120000) timeout = 120000; // Max 2 minutes
|
||||
+ }
|
||||
+ } else if (fade) {
|
||||
+ timeout = speed + 2000;
|
||||
+ }
|
||||
+
|
||||
+ if (timeout > 0) {
|
||||
+ PacketResponseNG resp;
|
||||
+ if (WaitForResponseTimeout(CMD_LED_CONTROL, &resp, timeout) == false) {
|
||||
+ PrintAndLogEx(WARNING, "command execution time out");
|
||||
+ return PM3_ETIMEOUT;
|
||||
+ }
|
||||
+ if (resp.status != PM3_SUCCESS) {
|
||||
+ PrintAndLogEx(ERR, "LED control command failed");
|
||||
+ return resp.status;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return PM3_SUCCESS;
|
||||
+}
|
||||
+
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"-------------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operation") " -----------------------"},
|
||||
@@ -1518,6 +1627,7 @@ static command_t CommandTable[] = {
|
||||
{"connect", CmdConnect, AlwaysAvailable, "Connect to the device via serial port"},
|
||||
{"dbg", CmdDbg, IfPm3Present, "Set device side debug level"},
|
||||
{"fpgaoff", CmdFPGAOff, IfPm3Present, "Turn off FPGA on device"},
|
||||
+ {"led", CmdLed, IfPm3Present, "Control LEDs with PWM brightness and effects"},
|
||||
{"lcd", CmdLCD, IfPm3Lcd, "Send command/data to LCD"},
|
||||
{"lcdreset", CmdLCDReset, IfPm3Lcd, "Hardware reset LCD"},
|
||||
{"ping", CmdPing, IfPm3Present, "Test if the Proxmark3 is responsive"},
|
||||
diff --git a/common_arm/ticks.c b/common_arm/ticks.c
|
||||
index 73182a1..1655241 100644
|
||||
--- a/common_arm/ticks.c
|
||||
+++ b/common_arm/ticks.c
|
||||
@@ -32,19 +32,19 @@ void SpinDelayUsPrecision(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 16) >> 5;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
- AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(1);
|
||||
|
||||
// 48 MHz / 32 gives 1.5 Mhz
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xFFFF; // Channel Period Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CPRDR = 0xFFFF; // Channel Period Register
|
||||
|
||||
- uint16_t end = AT91C_BASE_PWMC_CH0->PWMC_CCNTR + ticks;
|
||||
- if (end == 0) // AT91C_BASE_PWMC_CH0->PWMC_CCNTR is never == 0
|
||||
+ uint16_t end = AT91C_BASE_PWMC_CH1->PWMC_CCNTR + ticks;
|
||||
+ if (end == 0) // AT91C_BASE_PWMC_CH1->PWMC_CCNTR is never == 0
|
||||
end++; // so we have to end++ to avoid inivity loop
|
||||
|
||||
for (;;) {
|
||||
- uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t now = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
if (now == end)
|
||||
return;
|
||||
@@ -59,19 +59,19 @@ void SpinDelayUs(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 512) >> 10;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
- AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(1);
|
||||
|
||||
// 48 MHz / 1024 gives 46.875 kHz
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CPRDR = 0xffff; // Channel Period Register
|
||||
|
||||
- uint16_t end = AT91C_BASE_PWMC_CH0->PWMC_CCNTR + ticks;
|
||||
- if (end == 0) // AT91C_BASE_PWMC_CH0->PWMC_CCNTR is never == 0
|
||||
+ uint16_t end = AT91C_BASE_PWMC_CH1->PWMC_CCNTR + ticks;
|
||||
+ if (end == 0) // AT91C_BASE_PWMC_CH1->PWMC_CCNTR is never == 0
|
||||
end++; // so we have to end++ to avoid inivity loop
|
||||
|
||||
for (;;) {
|
||||
- uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t now = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
if (now == end)
|
||||
return;
|
||||
diff --git a/common_arm/usb_cdc.c b/common_arm/usb_cdc.c
|
||||
index ce7bda3..776b00f 100644
|
||||
--- a/common_arm/usb_cdc.c
|
||||
+++ b/common_arm/usb_cdc.c
|
||||
@@ -487,17 +487,17 @@ static void SpinDelayUs(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 512) >> 10;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
- AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
+ AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(1);
|
||||
|
||||
// 48 MHz / 1024 gives 46.875 kHz
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
- AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
+ AT91C_BASE_PWMC_CH1->PWMC_CPRDR = 0xffff; // Channel Period Register
|
||||
|
||||
- uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t start = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
|
||||
for (;;) {
|
||||
- uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
+ uint16_t now = AT91C_BASE_PWMC_CH1->PWMC_CCNTR;
|
||||
if (now == (uint16_t)(start + ticks))
|
||||
return;
|
||||
|
||||
diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h
|
||||
index 860dfa9..e1551b5 100644
|
||||
--- a/include/pm3_cmd.h
|
||||
+++ b/include/pm3_cmd.h
|
||||
@@ -465,6 +465,17 @@ typedef struct {
|
||||
uint8_t data[];
|
||||
} PACKED smart_card_raw_t;
|
||||
|
||||
+// For CMD_LED_CONTROL
|
||||
+// Actions: 0=off, 1=on, 2=toggle, 3=pwm, 4=pulse, 5=fade, 6=blink
|
||||
+typedef struct {
|
||||
+ uint8_t led; // LED bitmask: LED_A=1, LED_B=2, LED_C=4, LED_D=8
|
||||
+ uint8_t action; // 0=off, 1=on, 2=toggle, 3=pwm, 4=pulse, 5=fade, 6=blink
|
||||
+ uint8_t brightness; // 0-100 (for PWM-based actions)
|
||||
+ uint8_t reserved; // Reserved for alignment
|
||||
+ uint16_t speed_ms; // Effect cycle time in ms (default 500)
|
||||
+ uint16_t count; // Number of effect cycles (0=infinite)
|
||||
+} PACKED payload_led_control_t;
|
||||
+
|
||||
|
||||
// For the bootloader
|
||||
#define CMD_DEVICE_INFO 0x0000
|
||||
@@ -500,6 +507,7 @@ typedef struct {
|
||||
#define CMD_TIA 0x0117
|
||||
#define CMD_BREAK_LOOP 0x0118
|
||||
#define CMD_SET_TEAROFF 0x0119
|
||||
+#define CMD_LED_CONTROL 0x011A
|
||||
#define CMD_GET_DBGMODE 0x0120
|
||||
|
||||
// RDV40, Flash memory operations
|
||||
5
pi-gen/stageDangerousPi/02-pm3-install/pm3-version.conf
Normal file
5
pi-gen/stageDangerousPi/02-pm3-install/pm3-version.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
# Proxmark3 build version config
|
||||
# Change PM3_COMMIT to rebuild with a different upstream version.
|
||||
# Leave PM3_COMMIT empty to build from latest master (non-deterministic).
|
||||
PM3_REPO="https://github.com/RfidResearchGroup/proxmark3"
|
||||
PM3_COMMIT="ef82d5ba1"
|
||||
@@ -13,16 +13,8 @@ DEFAULT_HOME=$(eval echo ~$DEFAULT_USER)
|
||||
|
||||
echo "Detected default user: $DEFAULT_USER (home: $DEFAULT_HOME)"
|
||||
|
||||
# Install pip3 if not already installed
|
||||
if ! command -v pip3 &> /dev/null; then
|
||||
echo "Installing pip3..."
|
||||
apt-get update
|
||||
apt-get install -y python3-pip
|
||||
fi
|
||||
|
||||
# Install Node.js for frontend (Remix SSR) and utilities
|
||||
echo "Installing Node.js and utilities..."
|
||||
apt-get install -y nodejs npm lrzsz
|
||||
# Packages (nodejs, npm, lrzsz) installed by 00-apt-setup stage
|
||||
# pip3 is available from stage2 Python installation
|
||||
|
||||
# Install Python packages from requirements.txt
|
||||
pip3 install --break-system-packages -r /tmp/dangerous-pi-files/requirements.txt
|
||||
@@ -63,14 +55,28 @@ fi
|
||||
# Add user to netdev group for network management
|
||||
usermod -a -G netdev $DEFAULT_USER
|
||||
|
||||
# Build frontend (Remix SSR)
|
||||
echo "Building frontend..."
|
||||
# Frontend setup (Remix SSR)
|
||||
# build_frontend() in build-image.sh pre-builds on the host.
|
||||
# All production deps are pure JS (no native modules), so the host
|
||||
# node_modules works on arm64 without reinstalling.
|
||||
cd /opt/dangerous-pi/app/frontend
|
||||
npm ci --production=false # Install dev deps for build
|
||||
npm run build
|
||||
# Remove dev dependencies and node_modules bloat after build
|
||||
rm -rf node_modules/.cache
|
||||
npm prune --production
|
||||
if [ -d "build/server" ]; then
|
||||
echo "Using pre-built frontend from host..."
|
||||
# Remove build-time-only packages to save ~100MB of image space
|
||||
rm -rf node_modules/.cache \
|
||||
node_modules/@rollup \
|
||||
node_modules/@esbuild \
|
||||
node_modules/@remix-run/dev \
|
||||
node_modules/vite \
|
||||
node_modules/typescript \
|
||||
node_modules/@types
|
||||
else
|
||||
echo "Building frontend in chroot (no pre-built output found)..."
|
||||
npm install --production=false
|
||||
npm run build
|
||||
rm -rf node_modules/.cache
|
||||
npm prune --production
|
||||
fi
|
||||
cd /opt/dangerous-pi
|
||||
|
||||
# Install frontend systemd service
|
||||
@@ -26,4 +26,15 @@ echo "0.1.0-$(date +%Y%m%d)" > "${ROOTFS_DIR}/tmp/dangerous-pi-files/VERSION"
|
||||
mkdir -p "${ROOTFS_DIR}/tmp/dangerous-pi-files/data"
|
||||
mkdir -p "${ROOTFS_DIR}/tmp/dangerous-pi-files/logs"
|
||||
|
||||
# Copy dt-design-system to /opt/ so frontend's file: dependency resolves
|
||||
# Frontend package.json has: "@dangerousthings/web": "file:../../../dt-design-system/packages/web"
|
||||
# From /opt/dangerous-pi/app/frontend/, ../../../ resolves to /opt/
|
||||
if [ -d "${SCRIPT_DIR}/files/dt-design-system" ]; then
|
||||
echo "Copying dt-design-system for frontend dependency resolution..."
|
||||
mkdir -p "${ROOTFS_DIR}/opt/dt-design-system/packages"
|
||||
cp -r "${SCRIPT_DIR}/files/dt-design-system/packages/web" "${ROOTFS_DIR}/opt/dt-design-system/packages/"
|
||||
cp -r "${SCRIPT_DIR}/files/dt-design-system/packages/tokens" "${ROOTFS_DIR}/opt/dt-design-system/packages/"
|
||||
cp "${SCRIPT_DIR}/files/dt-design-system/package.json" "${ROOTFS_DIR}/opt/dt-design-system/"
|
||||
fi
|
||||
|
||||
echo "Files prepared successfully"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user