From 668e1bf71ab0d90ffeba5c9a96c9b31d80061bdf Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 13 Nov 2025 23:15:11 +0530 Subject: [PATCH 01/26] Add armhf dependencies --- .github/workflows/armhf-release.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index fb1f791..f9ef9a4 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -15,8 +15,13 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout + - name: Checkout uses: actions/checkout@v2 + - name: Install armhf dependencies + run: | + sudo dpkg --add-architecture armhf + sudo apt-get update + sudo apt-get install -y libnm-dev:armhf - name: Install Deps run: | sudo dpkg --add-architecture armhf From 7c6c6c29cda8984e3fb7e8e155d1b9a2c5814565 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 13 Nov 2025 23:19:15 +0530 Subject: [PATCH 02/26] Change ubuntu version --- .github/workflows/armhf-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index f9ef9a4..e08a900 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -12,7 +12,7 @@ env: jobs: armhf: name: build-armhf - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout From 774e1309dcd507fbfa46976c494ab12c48c769a0 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 13 Nov 2025 23:24:34 +0530 Subject: [PATCH 03/26] update workflow --- .github/workflows/armhf-release.yml | 88 ++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index e08a900..22e1621 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -17,54 +17,86 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Install armhf dependencies + + - name: Setup armhf architecture and repositories run: | sudo dpkg --add-architecture armhf - sudo apt-get update - sudo apt-get install -y libnm-dev:armhf - - name: Install Deps + + # Add Ubuntu ports repository for armhf packages + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + + # Update package lists + sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/armhf.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + + - name: Install cross-compilation tools run: | - sudo dpkg --add-architecture armhf - sudo apt install gcc-12-arm-linux-gnueabihf g++-12-arm-linux-gnueabihf libnm-dev:armhf libglib2.0-dev -y + sudo apt-get install -y \ + gcc-11-arm-linux-gnueabihf \ + g++-11-arm-linux-gnueabihf \ + crossbuild-essential-armhf + + - name: Install armhf libraries + run: | + sudo apt-get install -y \ + libnm-dev:armhf \ + libglib2.0-dev:armhf + + - name: Install native development packages + run: | + sudo apt-get install -y \ + cmake \ + build-essential \ + libglib2.0-dev + - name: Build - id: armhf-artifact-download + id: build-step run: | cd ${{ github.workspace }} mkdir build cd build - cmake .. -DCMAKE_CXX_COMPILER=$(which arm-linux-gnueabihf-g++-12) \ - -DCMAKE_C_COMPILER=$(which arm-linux-gnueabihf-gcc-12) \ - -DARMHF_DEB=ON \ - -DARCHITECTURE="armhf" \ - -DGIT_VERSION=$(echo ${{ github.ref }} | grep -o v'[0-9]\+\.[0-9]\+\.[0-9]\+') + + # Extract version from tag (remove 'v' prefix if present) + VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') + echo "Version: $VERSION" + + cmake .. \ + -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++-11 \ + -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc-11 \ + -DARMHF_DEB=ON \ + -DARCHITECTURE="armhf" \ + -DGIT_VERSION="$VERSION" + make -j$(nproc) make package - armhf__filename__=$(echo $(ls ${{steps.armhf-artifact-download.outputs.download-path}} | grep ..armhf.deb) | tr -d '\n') - name__=$(echo ${armhf__filename__%-*} | tr -d '\n') - version__=$(echo ${{ github.ref }} | grep -o v'[0-9]\+\.[0-9]\+\.[0-9]\+') - echo "name__=$name__" >> $GITHUB_ENV - echo "version__=$version__" >> $GITHUB_ENV - echo "armhf__filename__=$armhf__filename__" >> $GITHUB_ENV + + # Find the generated .deb file + ARMHF_FILENAME=$(ls *.deb | grep armhf | head -1) + echo "Generated package: $ARMHF_FILENAME" + + # Set environment variables for subsequent steps + echo "armhf_filename=$ARMHF_FILENAME" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_ENV + - name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ env.version__ }} - release_name: Release ${{ env.version__ }} - draft: false - prerelease: false + tag_name: ${{ github.ref_name }} + release_name: Release ${{ github.ref_name }} + draft: false + prerelease: false + - name: Upload Release Asset id: upload-release-asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, - # which include a `upload_url`. See this blog post for more info: - # https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ github.workspace }}/build/${{ env.armhf__filename__ }} - asset_name: ${{ env.armhf__filename__ }} - asset_content_type: application/vnd.debian.binary-package + asset_path: ${{ github.workspace }}/build/${{ env.armhf_filename }} + asset_name: ${{ env.armhf_filename }} + asset_content_type: application/vnd.debian.binary-package \ No newline at end of file From 98425d50a4549b438e4395f7dbb2fd936375eefb Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 13 Nov 2025 23:28:09 +0530 Subject: [PATCH 04/26] Added pkg-config-arm-linux-gnueabihf --- .github/workflows/armhf-release.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 22e1621..9bee7e0 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -28,14 +28,15 @@ jobs: echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list # Update package lists - sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/armhf.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + sudo apt-get update - name: Install cross-compilation tools run: | sudo apt-get install -y \ gcc-11-arm-linux-gnueabihf \ g++-11-arm-linux-gnueabihf \ - crossbuild-essential-armhf + crossbuild-essential-armhf \ + pkg-config-arm-linux-gnueabihf - name: Install armhf libraries run: | @@ -48,7 +49,8 @@ jobs: sudo apt-get install -y \ cmake \ build-essential \ - libglib2.0-dev + libglib2.0-dev \ + pkg-config - name: Build id: build-step @@ -61,9 +63,19 @@ jobs: VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') echo "Version: $VERSION" + # Set up environment for cross-compilation + export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig + export PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf/pkgconfig + export PKG_CONFIG_SYSROOT_DIR=/ + cmake .. \ -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++-11 \ -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc-11 \ + -DCMAKE_FIND_ROOT_PATH=/usr/arm-linux-gnueabihf \ + -DCMAKE_PREFIX_PATH=/usr/arm-linux-gnueabihf \ + -DCMAKE_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib \ + -DCMAKE_INCLUDE_PATH=/usr/arm-linux-gnueabihf/include \ + -DPKG_CONFIG_EXECUTABLE=/usr/bin/arm-linux-gnueabihf-pkg-config \ -DARMHF_DEB=ON \ -DARCHITECTURE="armhf" \ -DGIT_VERSION="$VERSION" From 1e7cb57fcc90b7ba32309804b48ac04284a5d78c Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 13 Nov 2025 23:31:29 +0530 Subject: [PATCH 05/26] Isolated armhf repository configuration --- .github/workflows/armhf-release.yml | 45 ++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 9bee7e0..c744600 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -22,16 +22,20 @@ jobs: run: | sudo dpkg --add-architecture armhf - # Add Ubuntu ports repository for armhf packages - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + # Remove any existing armhf.list to avoid conflicts + sudo rm -f /etc/apt/sources.list.d/armhf.list - # Update package lists - sudo apt-get update + # Create a clean sources.list.d for armhf with ONLY ports repository + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf-ports.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf-ports.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf-ports.list + + # Update package lists specifically for armhf + sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/armhf-ports.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" - name: Install cross-compilation tools run: | + sudo apt-get update sudo apt-get install -y \ gcc-11-arm-linux-gnueabihf \ g++-11-arm-linux-gnueabihf \ @@ -40,9 +44,11 @@ jobs: - name: Install armhf libraries run: | + # Install armhf packages using the ports repository sudo apt-get install -y \ libnm-dev:armhf \ - libglib2.0-dev:armhf + libglib2.0-dev:armhf \ + --allow-unauthenticated - name: Install native development packages run: | @@ -68,14 +74,25 @@ jobs: export PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf/pkgconfig export PKG_CONFIG_SYSROOT_DIR=/ + # Create a toolchain file for cross-compilation + cat > toolchain.cmake << 'EOF' + set(CMAKE_SYSTEM_NAME Linux) + set(CMAKE_SYSTEM_PROCESSOR arm) + + set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-11) + set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-11) + + set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + + set(PKG_CONFIG_EXECUTABLE /usr/bin/arm-linux-gnueabihf-pkg-config) + EOF + cmake .. \ - -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++-11 \ - -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc-11 \ - -DCMAKE_FIND_ROOT_PATH=/usr/arm-linux-gnueabihf \ - -DCMAKE_PREFIX_PATH=/usr/arm-linux-gnueabihf \ - -DCMAKE_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib \ - -DCMAKE_INCLUDE_PATH=/usr/arm-linux-gnueabihf/include \ - -DPKG_CONFIG_EXECUTABLE=/usr/bin/arm-linux-gnueabihf-pkg-config \ + -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \ -DARMHF_DEB=ON \ -DARCHITECTURE="armhf" \ -DGIT_VERSION="$VERSION" From 8bde1f4b600785ad3c8e79e648895b20a0b0ba72 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 12:43:01 +0530 Subject: [PATCH 06/26] Add arm64 --- .github/workflows/armhf-release.yml | 76 +++++++++++++++-------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index c744600..38e45d0 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -1,4 +1,4 @@ -name: armhf release +name: arm64 release on: push: @@ -10,44 +10,44 @@ env: BUILD_TYPE: Release jobs: - armhf: - name: build-armhf + arm64: + name: build-arm64 runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v2 - - name: Setup armhf architecture and repositories + - name: Setup arm64 architecture and repositories run: | - sudo dpkg --add-architecture armhf + sudo dpkg --add-architecture arm64 - # Remove any existing armhf.list to avoid conflicts - sudo rm -f /etc/apt/sources.list.d/armhf.list + # Remove any existing arm64.list to avoid conflicts + sudo rm -f /etc/apt/sources.list.d/arm64.list - # Create a clean sources.list.d for armhf with ONLY ports repository - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf-ports.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf-ports.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf-ports.list + # Create a clean sources.list.d for arm64 with ONLY ports repository + echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/arm64-ports.list + echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list + echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list - # Update package lists specifically for armhf - sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/armhf-ports.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + # Update package lists specifically for arm64 + sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/arm64-ports.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" - name: Install cross-compilation tools run: | sudo apt-get update sudo apt-get install -y \ - gcc-11-arm-linux-gnueabihf \ - g++-11-arm-linux-gnueabihf \ - crossbuild-essential-armhf \ - pkg-config-arm-linux-gnueabihf + gcc-11-aarch64-linux-gnu \ + g++-11-aarch64-linux-gnu \ + crossbuild-essential-arm64 \ + pkg-config-aarch64-linux-gnu - - name: Install armhf libraries + - name: Install arm64 libraries run: | - # Install armhf packages using the ports repository + # Install arm64 packages using the ports repository sudo apt-get install -y \ - libnm-dev:armhf \ - libglib2.0-dev:armhf \ + libnm-dev:arm64 \ + libglib2.0-dev:arm64 \ --allow-unauthenticated - name: Install native development packages @@ -70,42 +70,46 @@ jobs: echo "Version: $VERSION" # Set up environment for cross-compilation - export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig - export PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf/pkgconfig + export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig + export PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig export PKG_CONFIG_SYSROOT_DIR=/ - # Create a toolchain file for cross-compilation + # Create a toolchain file for cross-compilation with Cortex-A53 optimizations cat > toolchain.cmake << 'EOF' set(CMAKE_SYSTEM_NAME Linux) - set(CMAKE_SYSTEM_PROCESSOR arm) + set(CMAKE_SYSTEM_PROCESSOR aarch64) - set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-11) - set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-11) + set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc-11) + set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++-11) - set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf) + # PocketBeagle 2 specific optimizations for Cortex-A53 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe") + + set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(PKG_CONFIG_EXECUTABLE /usr/bin/arm-linux-gnueabihf-pkg-config) + set(PKG_CONFIG_EXECUTABLE /usr/bin/aarch64-linux-gnu-pkg-config) EOF cmake .. \ -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \ - -DARMHF_DEB=ON \ - -DARCHITECTURE="armhf" \ + -DARM64_DEB=ON \ + -DARCHITECTURE="arm64" \ -DGIT_VERSION="$VERSION" make -j$(nproc) make package # Find the generated .deb file - ARMHF_FILENAME=$(ls *.deb | grep armhf | head -1) - echo "Generated package: $ARMHF_FILENAME" + ARM64_FILENAME=$(ls *.deb | grep arm64 | head -1) + echo "Generated package: $ARM64_FILENAME" # Set environment variables for subsequent steps - echo "armhf_filename=$ARMHF_FILENAME" >> $GITHUB_ENV + echo "arm64_filename=$ARM64_FILENAME" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_ENV - name: Create Release @@ -126,6 +130,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ github.workspace }}/build/${{ env.armhf_filename }} - asset_name: ${{ env.armhf_filename }} + asset_path: ${{ github.workspace }}/build/${{ env.arm64_filename }} + asset_name: ${{ env.arm64_filename }} asset_content_type: application/vnd.debian.binary-package \ No newline at end of file From 9a17b3705d4504ddadfe01cea19d313d438482f9 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 12:47:44 +0530 Subject: [PATCH 07/26] WIP --- .github/workflows/armhf-release.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 38e45d0..1344206 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -2,9 +2,8 @@ name: arm64 release on: push: - # Sequence of patterns matched against refs/tags tags: - - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + - 'v*' env: BUILD_TYPE: Release @@ -22,20 +21,19 @@ jobs: run: | sudo dpkg --add-architecture arm64 - # Remove any existing arm64.list to avoid conflicts - sudo rm -f /etc/apt/sources.list.d/arm64.list + # Remove any existing arm64 lists to avoid conflicts + sudo rm -f /etc/apt/sources.list.d/armhf.list /etc/apt/sources.list.d/arm64.list 2>/dev/null || true - # Create a clean sources.list.d for arm64 with ONLY ports repository + # Create sources.list.d for arm64 with ONLY ports repository echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/arm64-ports.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list - # Update package lists specifically for arm64 - sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/arm64-ports.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" + # Update package lists for ALL architectures + sudo apt-get update - name: Install cross-compilation tools run: | - sudo apt-get update sudo apt-get install -y \ gcc-11-aarch64-linux-gnu \ g++-11-aarch64-linux-gnu \ @@ -44,18 +42,17 @@ jobs: - name: Install arm64 libraries run: | - # Install arm64 packages using the ports repository + # Install arm64 packages using apt-get with architecture specification sudo apt-get install -y \ libnm-dev:arm64 \ libglib2.0-dev:arm64 \ - --allow-unauthenticated + libc6-dev:arm64 - name: Install native development packages run: | sudo apt-get install -y \ cmake \ build-essential \ - libglib2.0-dev \ pkg-config - name: Build From 1773b375be33e39a1ae192ea99aa88ec56a833ab Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 12:51:06 +0530 Subject: [PATCH 08/26] WIP:ADD ARM64 --- .github/workflows/armhf-release.yml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 1344206..c9eaac8 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -21,15 +21,32 @@ jobs: run: | sudo dpkg --add-architecture arm64 - # Remove any existing arm64 lists to avoid conflicts - sudo rm -f /etc/apt/sources.list.d/armhf.list /etc/apt/sources.list.d/arm64.list 2>/dev/null || true + # Create a temporary apt configuration to ONLY use ports for arm64 + sudo mkdir -p /etc/apt/sources.list.d + sudo rm -f /etc/apt/sources.list.d/arm64-ports.list # Create sources.list.d for arm64 with ONLY ports repository echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/arm64-ports.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list - # Update package lists for ALL architectures + # Create apt preferences to prioritize ports repository for arm64 + sudo mkdir -p /etc/apt/preferences.d + cat << EOF | sudo tee /etc/apt/preferences.d/arm64-ports + Package: * + Pin: release a=jammy + Pin-Priority: 500 + + Package: * + Pin: release o=Ubuntu,a=jammy + Pin-Priority: 500 + + Package: * + Pin: release l=UbuntuPorts + Pin-Priority: 1000 + EOF + + # Update package lists sudo apt-get update - name: Install cross-compilation tools @@ -42,7 +59,7 @@ jobs: - name: Install arm64 libraries run: | - # Install arm64 packages using apt-get with architecture specification + # Install arm64 packages - they should come from ports repository sudo apt-get install -y \ libnm-dev:arm64 \ libglib2.0-dev:arm64 \ From 85f6f159e66bcd20d3530afe38bc84886d9dbaf6 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 12:55:20 +0530 Subject: [PATCH 09/26] WIP:QEMU --- .github/workflows/armhf-release.yml | 160 +++++++++------------------- 1 file changed, 52 insertions(+), 108 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index c9eaac8..ca0d9e2 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -5,127 +5,72 @@ on: tags: - 'v*' -env: - BUILD_TYPE: Release - jobs: arm64: - name: build-arm64 + name: build-arm64-native runs-on: ubuntu-22.04 - + steps: - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Setup arm64 architecture and repositories - run: | - sudo dpkg --add-architecture arm64 - - # Create a temporary apt configuration to ONLY use ports for arm64 - sudo mkdir -p /etc/apt/sources.list.d - sudo rm -f /etc/apt/sources.list.d/arm64-ports.list - - # Create sources.list.d for arm64 with ONLY ports repository - echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/arm64-ports.list - echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list - echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/arm64-ports.list - - # Create apt preferences to prioritize ports repository for arm64 - sudo mkdir -p /etc/apt/preferences.d - cat << EOF | sudo tee /etc/apt/preferences.d/arm64-ports - Package: * - Pin: release a=jammy - Pin-Priority: 500 - Package: * - Pin: release o=Ubuntu,a=jammy - Pin-Priority: 500 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: arm64 - Package: * - Pin: release l=UbuntuPorts - Pin-Priority: 1000 - EOF - - # Update package lists - sudo apt-get update - - - name: Install cross-compilation tools - run: | - sudo apt-get install -y \ - gcc-11-aarch64-linux-gnu \ - g++-11-aarch64-linux-gnu \ - crossbuild-essential-arm64 \ - pkg-config-aarch64-linux-gnu - - - name: Install arm64 libraries - run: | - # Install arm64 packages - they should come from ports repository - sudo apt-get install -y \ - libnm-dev:arm64 \ - libglib2.0-dev:arm64 \ - libc6-dev:arm64 - - - name: Install native development packages - run: | - sudo apt-get install -y \ - cmake \ - build-essential \ - pkg-config - - - name: Build - id: build-step + - name: Build using Docker run: | - cd ${{ github.workspace }} - mkdir build - cd build - - # Extract version from tag (remove 'v' prefix if present) + # Extract version from tag VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') - echo "Version: $VERSION" - - # Set up environment for cross-compilation - export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig - export PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig - export PKG_CONFIG_SYSROOT_DIR=/ - - # Create a toolchain file for cross-compilation with Cortex-A53 optimizations - cat > toolchain.cmake << 'EOF' - set(CMAKE_SYSTEM_NAME Linux) - set(CMAKE_SYSTEM_PROCESSOR aarch64) - - set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc-11) - set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++-11) + echo "Building version: $VERSION" - # PocketBeagle 2 specific optimizations for Cortex-A53 - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe") - - set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - - set(PKG_CONFIG_EXECUTABLE /usr/bin/aarch64-linux-gnu-pkg-config) + # Create a Dockerfile for native ARM64 build + cat > Dockerfile << EOF + FROM arm64v8/ubuntu:22.04 + + # Set up environment + ENV DEBIAN_FRONTEND=noninteractive + + # Update and install dependencies + RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + pkg-config \ + libnm-dev \ + libglib2.0-dev \ + debhelper \ + dh-make \ + git \ + && rm -rf /var/lib/apt/lists/* + + WORKDIR /build + COPY . . + + RUN mkdir build && cd build && \ + cmake .. \ + -DCMAKE_C_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ + -DCMAKE_CXX_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ + -DARCHITECTURE="arm64" \ + -DGIT_VERSION="$VERSION" && \ + make -j\$(nproc) && \ + make package EOF + + # Build using Docker + docker build --build-arg VERSION=$VERSION -t arm64-builder . - cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \ - -DARM64_DEB=ON \ - -DARCHITECTURE="arm64" \ - -DGIT_VERSION="$VERSION" - - make -j$(nproc) - make package + # Extract the built package + docker create --name builder arm64-builder + docker cp builder:/build/build/ ./ + docker rm builder # Find the generated .deb file - ARM64_FILENAME=$(ls *.deb | grep arm64 | head -1) + ARM64_FILENAME=$(ls build/*.deb | head -1) echo "Generated package: $ARM64_FILENAME" - - # Set environment variables for subsequent steps - echo "arm64_filename=$ARM64_FILENAME" >> $GITHUB_ENV + echo "arm64_filename=$(basename $ARM64_FILENAME)" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_ENV - + - name: Create Release id: create_release uses: actions/create-release@v1 @@ -136,14 +81,13 @@ jobs: release_name: Release ${{ github.ref_name }} draft: false prerelease: false - + - name: Upload Release Asset - id: upload-release-asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ github.workspace }}/build/${{ env.arm64_filename }} + asset_path: ./build/${{ env.arm64_filename }} asset_name: ${{ env.arm64_filename }} asset_content_type: application/vnd.debian.binary-package \ No newline at end of file From 409fadd72a0db8a02a9f457c11ab128798925863 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 12:57:50 +0530 Subject: [PATCH 10/26] WIP:Add buildx --- .github/workflows/armhf-release.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index ca0d9e2..803664c 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -19,15 +19,18 @@ jobs: with: platforms: arm64 - - name: Build using Docker + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build ARM64 package run: | # Extract version from tag VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') echo "Building version: $VERSION" # Create a Dockerfile for native ARM64 build - cat > Dockerfile << EOF - FROM arm64v8/ubuntu:22.04 + cat > Dockerfile << 'EOF' + FROM ubuntu:22.04 # Set up environment ENV DEBIAN_FRONTEND=noninteractive @@ -53,14 +56,18 @@ jobs: -DCMAKE_CXX_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ -DARCHITECTURE="arm64" \ -DGIT_VERSION="$VERSION" && \ - make -j\$(nproc) && \ + make -j$(nproc) && \ make package EOF - # Build using Docker - docker build --build-arg VERSION=$VERSION -t arm64-builder . + # Build for ARM64 using buildx + docker buildx build \ + --platform linux/arm64 \ + --tag arm64-builder \ + --load \ + . - # Extract the built package + # Create container and extract package docker create --name builder arm64-builder docker cp builder:/build/build/ ./ docker rm builder From 87338e032ad8e949ab7d28f6e19acbe11221f24c Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Thu, 20 Nov 2025 13:13:37 +0530 Subject: [PATCH 11/26] WIP:Add deb lib --- .github/workflows/armhf-release.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 803664c..8be3c21 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -7,7 +7,7 @@ on: jobs: arm64: - name: build-arm64-native + name: build-arm64-deb runs-on: ubuntu-22.04 steps: @@ -22,11 +22,11 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Build ARM64 package + - name: Build ARM64 Debian package run: | # Extract version from tag VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') - echo "Building version: $VERSION" + echo "Building version: $VERSION for PocketBeagle 2 (ARM64)" # Create a Dockerfile for native ARM64 build cat > Dockerfile << 'EOF' @@ -57,7 +57,8 @@ jobs: -DARCHITECTURE="arm64" \ -DGIT_VERSION="$VERSION" && \ make -j$(nproc) && \ - make package + # Generate DEB package with proper architecture + cpack -G DEB -D CPACK_DEBIAN_PACKAGE_ARCHITECTURE=arm64 EOF # Build for ARM64 using buildx @@ -74,10 +75,23 @@ jobs: # Find the generated .deb file ARM64_FILENAME=$(ls build/*.deb | head -1) + if [ -z "$ARM64_FILENAME" ]; then + echo "Error: No .deb file found!" + ls -la build/ + exit 1 + fi + echo "Generated package: $ARM64_FILENAME" echo "arm64_filename=$(basename $ARM64_FILENAME)" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_ENV + - name: Verify Debian package + run: | + echo "Verifying Debian package structure..." + dpkg-deb -I ./build/${{ env.arm64_filename }} + echo "Package contents:" + dpkg-deb -c ./build/${{ env.arm64_filename }} + - name: Create Release id: create_release uses: actions/create-release@v1 From adbf8dfabe36b6834a1b27059f04914af8f2a067 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Fri, 12 Dec 2025 23:35:49 +0530 Subject: [PATCH 12/26] Update gpio method --- src/ui/panel/gpio/gpio_impl.cpp | 144 +++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 29 deletions(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index bb3c065..ebce00b 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "ftxui/component/component.hpp" #include "ftxui/dom/elements.hpp" #include "ui/panel/panel.hpp" @@ -48,11 +49,40 @@ class Gpio : public ComponentBase { private: void Fetch() { - std::ifstream(path_ + "/label") >> label_; - std::ifstream(path_ + "/edge") >> edge_; - std::ifstream(path_ + "/direction") >> direction_; - std::ifstream(path_ + "/value") >> value_; - std::ifstream(path_ + "/active_low") >> active_low_; + std::ifstream label_file(path_ + "/label"); + if (label_file.is_open()) { + std::getline(label_file, label_); + } else { + label_ = "Unknown"; + } + + std::ifstream edge_file(path_ + "/edge"); + if (edge_file.is_open()) { + std::getline(edge_file, edge_); + } else { + edge_ = "none"; + } + + std::ifstream direction_file(path_ + "/direction"); + if (direction_file.is_open()) { + std::getline(direction_file, direction_); + } else { + direction_ = "in"; + } + + std::ifstream value_file(path_ + "/value"); + if (value_file.is_open()) { + std::getline(value_file, value_); + } else { + value_ = "0"; + } + + std::ifstream active_low_file(path_ + "/active_low"); + if (active_low_file.is_open()) { + std::getline(active_low_file, active_low_); + } else { + active_low_ = "0"; + } } void StoreDirection(std::string direction) { @@ -126,6 +156,17 @@ class Gpio : public ComponentBase { valToggle = Menu(&valueEntries, &valTog, valueToggleOpt); activeToggle = Menu(&activeEntries, &activeTog, activeToggleOpt); edgeToggle = Menu(&edgeEntries, &edgeTog, edgeToggleOpt); + + // Set toggle states based on current values + ioTog = (direction_ == "out") ? 1 : 0; + valTog = (value_ == "1") ? 1 : 0; + activeTog = (active_low_ == "1") ? 1 : 0; + + if (edge_ == "rising") edgeTog = 0; + else if (edge_ == "falling") edgeTog = 1; + else if (edge_ == "both") edgeTog = 2; + else edgeTog = 3; + Component actions = Renderer( Container::Vertical({ ioToggle, @@ -135,11 +176,11 @@ class Gpio : public ComponentBase { }), [&] { return vbox({ - text(label() + " Status "), - hbox(text(" * Direction : "), text(direction())), - hbox(text(" * Value : "), text(value())), - hbox(text(" * Active Low : "), text(active_low())), - hbox(text(" * Edge : "), text(edge())), + text(label_ + " Status "), + hbox(text(" * Direction : "), text(direction_)), + hbox(text(" * Value : "), text(value_)), + hbox(text(" * Active Low : "), text(active_low_)), + hbox(text(" * Edge : "), text(edge_)), text(" Actions "), hbox(text(" * Direction : "), ioToggle->Render()), hbox(text(" * Value : "), valToggle->Render()), @@ -154,13 +195,13 @@ class Gpio : public ComponentBase { [&] { (*next_)--; if (*next_ < 0) { - *next_ = 0; + *next_ = (*limit_ > 0) ? *limit_ - 1 : 0; } }), Button("Next", [&] { (*next_)++; - if (*limit_ < *next_) { + if (*next_ >= *limit_) { *next_ = 0; } }), @@ -176,10 +217,10 @@ class Gpio : public ComponentBase { int* tab_; int* next_; int* limit_; - int ioTog; - int activeTog; - int valTog; - int edgeTog; + int ioTog = 0; + int activeTog = 0; + int valTog = 0; + int edgeTog = 3; Component ioToggle; Component activeToggle; Component valToggle; @@ -192,18 +233,55 @@ class GPIOImpl : public PanelBase { std::string Title() override { return "GPIO"; } private: + // Helper function to check if a GPIO is a P1/P2 pin + bool isBeagleBonePin(const std::string& label) { + // Check for P1 or P2 pins using regex + std::regex pin_pattern(R"(P[12]\.\d+)"); + if (std::regex_search(label, pin_pattern)) { + return true; + } + + // Also check for pins that have (P1.x) or (P2.x) in parentheses + std::regex paren_pattern(R"(\(P[12]\.\d+[^)]*\))"); + if (std::regex_search(label, paren_pattern)) { + return true; + } + + return false; + } + void BuildUI() { MenuOption menuOpt; menuOpt.on_enter = [&] { tab = 1; }; gpio_menu = Menu(&gpio_names, &selected, menuOpt); gpio_individual = Container::Vertical({}, &selected); - for (const auto& it : - std::filesystem::directory_iterator("/sys/class/gpio/")) { + + // First, let's look at all GPIO directories + for (const auto& it : std::filesystem::directory_iterator("/sys/class/gpio/")) { std::string gpio_path = it.path(); - if (gpio_path.find("gpiochip") == std::string::npos && - gpio_path.find("gpio") != std::string::npos) { - auto gpio = std::make_shared(gpio_path, &tab, &selected, &limit); - if (gpio->label().find("P") != std::string::npos) { + + // Skip gpiochip directories + if (gpio_path.find("gpiochip") != std::string::npos) { + continue; + } + + // Check if it's a GPIO directory (starts with "gpio") + if (gpio_path.find("/sys/class/gpio/gpio") == 0) { + // Read the label + std::string label_path = gpio_path + "/label"; + std::ifstream label_file(label_path); + std::string label; + + if (label_file.is_open()) { + std::getline(label_file, label); + } else { + // If no label file, use the GPIO number + label = it.path().filename().string(); + } + + // Check if this is a P1/P2 pin + if (isBeagleBonePin(label)) { + auto gpio = std::make_shared(gpio_path, &tab, &selected, &limit); children_.push_back(gpio); gpio_individual->Add(gpio); limit++; @@ -225,14 +303,22 @@ class GPIOImpl : public PanelBase { gpio_names.push_back(child->label()); } - int i = 0; - if (tab == 1) - for (const auto& child : children_) { - if (i == selected) { - return child->Render(); + if (tab == 1) { + if (children_.empty()) { + return window(text("GPIO Control"), + text("No GPIO pins found. Try exporting GPIOs first.") | + center | flex); + } + + if (selected >= 0 && selected < static_cast(children_.size())) { + return children_[selected]->Render(); + } else { + selected = 0; + if (!children_.empty()) { + return children_[0]->Render(); } - i++; } + } return window(text("GPIO Menu"), gpio_menu->Render() | vscroll_indicator | frame | flex); @@ -252,4 +338,4 @@ Panel GPIO() { return Make(); } } // namespace panel -} // namespace ui +} // namespace ui \ No newline at end of file From 3a909b8e1b0812f6a51a02b0cd7c5b87f8d296f3 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sat, 13 Dec 2025 01:26:56 +0530 Subject: [PATCH 13/26] Update gpio --- src/ui/panel/gpio/gpio_impl.cpp | 237 +++++++++++++++++++++++++------- 1 file changed, 187 insertions(+), 50 deletions(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index ebce00b..43466a8 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -1,6 +1,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include // for usleep #include "ftxui/component/component.hpp" #include "ftxui/dom/elements.hpp" #include "ui/panel/panel.hpp" @@ -33,10 +41,12 @@ const std::vector edgeEntries = { class Gpio : public ComponentBase { public: - Gpio(std::string path, int* tab, int* next, int* limit) : path_(path) { + Gpio(std::string gpio_num, std::string label, int* tab, int* next, int* limit) + : gpio_num_(gpio_num), label_(label) { limit_ = limit; tab_ = tab; next_ = next; + path_ = "/sys/class/gpio/gpio" + gpio_num; Fetch(); BuildUI(); } @@ -49,13 +59,15 @@ class Gpio : public ComponentBase { private: void Fetch() { - std::ifstream label_file(path_ + "/label"); - if (label_file.is_open()) { - std::getline(label_file, label_); + // Read direction + std::ifstream direction_file(path_ + "/direction"); + if (direction_file.is_open()) { + std::getline(direction_file, direction_); } else { - label_ = "Unknown"; + direction_ = "in"; } + // Read edge std::ifstream edge_file(path_ + "/edge"); if (edge_file.is_open()) { std::getline(edge_file, edge_); @@ -63,13 +75,7 @@ class Gpio : public ComponentBase { edge_ = "none"; } - std::ifstream direction_file(path_ + "/direction"); - if (direction_file.is_open()) { - std::getline(direction_file, direction_); - } else { - direction_ = "in"; - } - + // Read value std::ifstream value_file(path_ + "/value"); if (value_file.is_open()) { std::getline(value_file, value_); @@ -77,6 +83,7 @@ class Gpio : public ComponentBase { value_ = "0"; } + // Read active_low std::ifstream active_low_file(path_ + "/active_low"); if (active_low_file.is_open()) { std::getline(active_low_file, active_low_); @@ -176,7 +183,7 @@ class Gpio : public ComponentBase { }), [&] { return vbox({ - text(label_ + " Status "), + text(label_ + " (GPIO " + gpio_num_ + ") Status "), hbox(text(" * Direction : "), text(direction_)), hbox(text(" * Value : "), text(value_)), hbox(text(" * Active Low : "), text(active_low_)), @@ -209,6 +216,7 @@ class Gpio : public ComponentBase { } std::string path_; + std::string gpio_num_; std::string label_; std::string direction_; std::string edge_; @@ -227,67 +235,174 @@ class Gpio : public ComponentBase { Component edgeToggle; }; +// Helper function to execute shell command and get output +std::string exec(const char* cmd) { + std::array buffer; + std::string result; + std::unique_ptr pipe(popen(cmd, "r"), pclose); + if (!pipe) { + return ""; + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} + class GPIOImpl : public PanelBase { public: GPIOImpl() { BuildUI(); } std::string Title() override { return "GPIO"; } private: - // Helper function to check if a GPIO is a P1/P2 pin - bool isBeagleBonePin(const std::string& label) { - // Check for P1 or P2 pins using regex - std::regex pin_pattern(R"(P[12]\.\d+)"); - if (std::regex_search(label, pin_pattern)) { - return true; + // Get GPIO pin information using gpioinfo + std::vector> getGpioPins() { + std::vector> pins; + + std::string output = exec("gpioinfo 2>/dev/null"); + if (output.empty()) { + return pins; } - // Also check for pins that have (P1.x) or (P2.x) in parentheses - std::regex paren_pattern(R"(\(P[12]\.\d+[^)]*\))"); - if (std::regex_search(label, paren_pattern)) { + std::istringstream iss(output); + std::string line; + + // Chip number to GPIO base mapping (from your earlier output) + std::map chip_to_base = { + {0, 512}, // gpiochip0 -> base 512 + {1, 515}, // gpiochip1 -> base 515 + {2, 539}, // gpiochip2 -> base 539 + {3, 631}, // gpiochip3 -> base 631 + {4, 683}, // gpiochip4 -> base 683 + }; + + int current_chip = -1; + + while (std::getline(iss, line)) { + // Check for chip header + if (line.find("gpiochip") != std::string::npos) { + // Extract chip number + size_t chip_pos = line.find("gpiochip"); + if (chip_pos != std::string::npos) { + std::string chip_num_str; + for (size_t i = chip_pos + 8; i < line.size() && isdigit(line[i]); i++) { + chip_num_str += line[i]; + } + if (!chip_num_str.empty()) { + current_chip = std::stoi(chip_num_str); + } + } + continue; + } + + // Check for pin line + if (line.find("line") != std::string::npos && current_chip >= 0 && + chip_to_base.find(current_chip) != chip_to_base.end()) { + + // Extract line number + size_t line_pos = line.find("line"); + if (line_pos != std::string::npos) { + // Find the colon after line number + size_t colon_pos = line.find(":", line_pos); + if (colon_pos != std::string::npos) { + // Get line number string (between "line" and ":") + std::string line_num_str = line.substr(line_pos + 4, colon_pos - line_pos - 4); + + // Clean up the string + line_num_str.erase(0, line_num_str.find_first_not_of(" \t")); + line_num_str.erase(line_num_str.find_last_not_of(" \t") + 1); + + if (!line_num_str.empty()) { + int line_num = std::stoi(line_num_str); + + // Extract label - look for text in quotes + std::string label; + size_t quote_start = line.find('\"'); + if (quote_start != std::string::npos) { + size_t quote_end = line.find('\"', quote_start + 1); + if (quote_end != std::string::npos) { + label = line.substr(quote_start + 1, quote_end - quote_start - 1); + } + } + + // Check if it's a P1/P2 pin or USR_LED + if (!label.empty() && + (label.find("P1.") != std::string::npos || + label.find("P2.") != std::string::npos || + label.find("USR_LED") != std::string::npos)) { + + // Calculate GPIO number + int base = chip_to_base[current_chip]; + int gpio_num = base + line_num; + + pins.push_back({gpio_num, label}); + } + } + } + } + } + } + + return pins; + } + + // Export a GPIO if not already exported + bool exportGpio(int gpio_num) { + std::string gpio_path = "/sys/class/gpio/gpio" + std::to_string(gpio_num); + + // Check if already exported + if (std::filesystem::exists(gpio_path)) { return true; } + // Try to export + std::ofstream export_file("/sys/class/gpio/export"); + if (export_file.is_open()) { + export_file << gpio_num; + export_file.close(); + + // Wait for export to complete + usleep(50000); // 50ms + + return std::filesystem::exists(gpio_path); + } + return false; } void BuildUI() { + // Get list of GPIO pins from gpioinfo + auto gpio_pins = getGpioPins(); + MenuOption menuOpt; menuOpt.on_enter = [&] { tab = 1; }; gpio_menu = Menu(&gpio_names, &selected, menuOpt); gpio_individual = Container::Vertical({}, &selected); - // First, let's look at all GPIO directories - for (const auto& it : std::filesystem::directory_iterator("/sys/class/gpio/")) { - std::string gpio_path = it.path(); - - // Skip gpiochip directories - if (gpio_path.find("gpiochip") != std::string::npos) { - continue; - } - - // Check if it's a GPIO directory (starts with "gpio") - if (gpio_path.find("/sys/class/gpio/gpio") == 0) { - // Read the label - std::string label_path = gpio_path + "/label"; - std::ifstream label_file(label_path); - std::string label; + if (!gpio_pins.empty()) { + // Process pins from gpioinfo + for (const auto& pin : gpio_pins) { + int gpio_num = pin.first; + std::string label = pin.second; - if (label_file.is_open()) { - std::getline(label_file, label); - } else { - // If no label file, use the GPIO number - label = it.path().filename().string(); - } - - // Check if this is a P1/P2 pin - if (isBeagleBonePin(label)) { - auto gpio = std::make_shared(gpio_path, &tab, &selected, &limit); + // Try to export the GPIO + if (exportGpio(gpio_num)) { + std::string gpio_num_str = std::to_string(gpio_num); + auto gpio = std::make_shared(gpio_num_str, label, &tab, &selected, &limit); children_.push_back(gpio); gpio_individual->Add(gpio); limit++; } } } + + // If no pins found, show error message + if (children_.empty()) { + error_message_ = "No GPIO pins found. Make sure:\n" + "1. gpiod is installed (sudo apt-get install gpiod)\n" + "2. Run with sudo privileges\n" + "3. GPIOs are accessible"; + } Add(Container::Tab( { @@ -306,8 +421,18 @@ class GPIOImpl : public PanelBase { if (tab == 1) { if (children_.empty()) { return window(text("GPIO Control"), - text("No GPIO pins found. Try exporting GPIOs first.") | - center | flex); + vbox({ + text("No GPIO pins found."), + text(""), + text("Possible issues:"), + text("1. gpiod not installed - run: sudo apt-get install gpiod"), + text("2. Need sudo privileges - run program with sudo"), + text("3. GPIOs not exported - run export script"), + text(""), + text("Try running:"), + text(" sudo ./export_beaglebone_pins.sh"), + text(" sudo gpioinfo") + }) | center | flex); } if (selected >= 0 && selected < static_cast(children_.size())) { @@ -320,7 +445,18 @@ class GPIOImpl : public PanelBase { } } - return window(text("GPIO Menu"), + // Display GPIO menu + if (children_.empty()) { + return window(text("GPIO Menu"), + vbox({ + text("Available GPIOs: 0"), + text(""), + text("No GPIO pins detected."), + text("Try running with sudo or check installation.") + }) | center | flex); + } + + return window(text("GPIO Menu - " + std::to_string(children_.size()) + " pins"), gpio_menu->Render() | vscroll_indicator | frame | flex); } @@ -328,6 +464,7 @@ class GPIOImpl : public PanelBase { std::vector gpio_names; Component gpio_menu; Component gpio_individual; + std::string error_message_; int selected = 0; int tab = 0; int limit = 0; From fcd691a8b1eb6eb4698281dd2c5e2d55407df1fe Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Mon, 15 Dec 2025 23:23:10 +0530 Subject: [PATCH 14/26] ci: merge ARM workflows into single cross-platform pipeline for arm64 and armhf builds --- .github/workflows/armhf-release.yml | 271 ++++++++++++++++++++-------- 1 file changed, 197 insertions(+), 74 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 8be3c21..9c09af0 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -1,96 +1,191 @@ -name: arm64 release +name: ARM Cross-Platform Release on: push: tags: - - 'v*' + - 'v*' + +env: + BUILD_TYPE: Release jobs: - arm64: - name: build-arm64-deb + build-arm-packages: + name: Build ARM Packages runs-on: ubuntu-22.04 + strategy: + matrix: + arch: [arm64, armhf] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Extract Version + run: | + VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "Building version: $VERSION" - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + - name: Setup QEMU (for ARM64) + if: matrix.arch == 'arm64' + uses: docker/setup-qemu-action@v3 with: platforms: arm64 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + - name: Setup Buildx + if: matrix.arch == 'arm64' + uses: docker/setup-buildx-action@v3 - - name: Build ARM64 Debian package + - name: Install Cross-Compiler Dependencies (for ARMHF) + if: matrix.arch == 'armhf' run: | - # Extract version from tag - VERSION=$(echo "${{ github.ref }}" | sed 's/refs\/tags\///g' | sed 's/^v//') - echo "Building version: $VERSION for PocketBeagle 2 (ARM64)" - - # Create a Dockerfile for native ARM64 build - cat > Dockerfile << 'EOF' - FROM ubuntu:22.04 + sudo dpkg --add-architecture armhf + sudo apt-get update + sudo apt-get install -y \ + gcc-12-arm-linux-gnueabihf \ + g++-12-arm-linux-gnueabihf \ + libnm-dev:armhf \ + libglib2.0-dev:armhf \ + cmake \ + build-essential \ + pkg-config \ + debhelper \ + dh-make \ + file - # Set up environment - ENV DEBIAN_FRONTEND=noninteractive - - # Update and install dependencies - RUN apt-get update && apt-get install -y \ - build-essential \ - cmake \ - pkg-config \ - libnm-dev \ - libglib2.0-dev \ - debhelper \ - dh-make \ - git \ - && rm -rf /var/lib/apt/lists/* - - WORKDIR /build - COPY . . - - RUN mkdir build && cd build && \ - cmake .. \ - -DCMAKE_C_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ - -DCMAKE_CXX_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ - -DARCHITECTURE="arm64" \ - -DGIT_VERSION="$VERSION" && \ - make -j$(nproc) && \ - # Generate DEB package with proper architecture - cpack -G DEB -D CPACK_DEBIAN_PACKAGE_ARCHITECTURE=arm64 - EOF - - # Build for ARM64 using buildx - docker buildx build \ - --platform linux/arm64 \ - --tag arm64-builder \ - --load \ - . + - name: Build Package + run: | + echo "Building for ${{ matrix.arch }}" - # Create container and extract package - docker create --name builder arm64-builder - docker cp builder:/build/build/ ./ - docker rm builder + if [ "${{ matrix.arch }}" = "arm64" ]; then + # Build ARM64 using Docker/QEMU emulation + echo "Building ARM64 package using Docker" + + cat > Dockerfile.build << 'EOF' + FROM ubuntu:22.04 + + ENV DEBIAN_FRONTEND=noninteractive + + RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + pkg-config \ + libnm-dev \ + libglib2.0-dev \ + debhelper \ + dh-make \ + git \ + file \ + && rm -rf /var/lib/apt/lists/* + + WORKDIR /build + COPY . . + + RUN mkdir -p build && cd build && \ + cmake .. \ + -DCMAKE_C_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ + -DCMAKE_CXX_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ + -DARCHITECTURE="arm64" \ + -DGIT_VERSION="${{ env.VERSION }}" && \ + make -j$(nproc) && \ + cpack -G DEB -D CPACK_DEBIAN_PACKAGE_ARCHITECTURE=arm64 + EOF + + docker buildx build \ + --platform linux/arm64 \ + --tag arm64-builder \ + --load \ + -f Dockerfile.build \ + . + + docker create --name builder arm64-builder + docker cp builder:/build/build/ ./ + docker rm builder + + # Find and rename the generated .deb file + DEB_FILE=$(find build -name "*.deb" -type f | head -1) + if [ -n "$DEB_FILE" ]; then + mv "$DEB_FILE" "package_${{ matrix.arch }}.deb" + fi + + else + # Build ARMHF using cross-compiler + echo "Building ARMHF package using cross-compiler" + + mkdir -p build_armhf + cd build_armhf + + cmake .. \ + -DCMAKE_CXX_COMPILER=$(which arm-linux-gnueabihf-g++-12) \ + -DCMAKE_C_COMPILER=$(which arm-linux-gnueabihf-gcc-12) \ + -DARCHITECTURE="armhf" \ + -DGIT_VERSION="${{ env.VERSION }}" + + make -j$(nproc) + make package + + # Find and rename the generated .deb file + DEB_FILE=$(find . -name "*armhf.deb" -type f | head -1) + if [ -n "$DEB_FILE" ]; then + mv "$DEB_FILE" "../package_${{ matrix.arch }}.deb" + fi + fi + + - name: Verify Package + run: | + echo "Verifying ${{ matrix.arch }} package..." - # Find the generated .deb file - ARM64_FILENAME=$(ls build/*.deb | head -1) - if [ -z "$ARM64_FILENAME" ]; then - echo "Error: No .deb file found!" - ls -la build/ + if [ -f "package_${{ matrix.arch }}.deb" ]; then + echo "Package file: package_${{ matrix.arch }}.deb" + echo "Package info:" + dpkg-deb -I "package_${{ matrix.arch }}.deb" || true + + # Get actual filename for artifact + ORIG_NAME=$(basename $(dpkg-deb -f "package_${{ matrix.arch }}.deb" Package)_$(dpkg-deb -f "package_${{ matrix.arch }}.deb" Version)_${{ matrix.arch }}.deb) + echo "ORIG_NAME=$ORIG_NAME" >> $GITHUB_ENV + mv "package_${{ matrix.arch }}.deb" "$ORIG_NAME" + else + echo "ERROR: No package file found for ${{ matrix.arch }}!" + ls -la exit 1 fi - - echo "Generated package: $ARM64_FILENAME" - echo "arm64_filename=$(basename $ARM64_FILENAME)" >> $GITHUB_ENV - echo "version=$VERSION" >> $GITHUB_ENV - - name: Verify Debian package + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.arch }}-package + path: ${{ env.ORIG_NAME }} + retention-days: 5 + + create-release: + name: Create Release and Upload Assets + runs-on: ubuntu-22.04 + needs: build-arm-packages + if: success() + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Download ARM64 Artifact + uses: actions/download-artifact@v3 + with: + name: arm64-package + path: artifacts/ + + - name: Download ARMHF Artifact + uses: actions/download-artifact@v3 + with: + name: armhf-package + path: artifacts/ + + - name: Extract Version run: | - echo "Verifying Debian package structure..." - dpkg-deb -I ./build/${{ env.arm64_filename }} - echo "Package contents:" - dpkg-deb -c ./build/${{ env.arm64_filename }} + VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "Creating release for version: $VERSION" - name: Create Release id: create_release @@ -102,13 +197,41 @@ jobs: release_name: Release ${{ github.ref_name }} draft: false prerelease: false + body: | + ARM Cross-Platform Release + + This release contains packages for both ARM architectures: + - **ARM64** (64-bit): For PocketBeagle 2 and other ARMv8/AArch64 devices + - **ARMHF** (32-bit): For ARMv7 devices with hard-float ABI - - name: Upload Release Asset + - name: Upload ARM64 Asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./build/${{ env.arm64_filename }} - asset_name: ${{ env.arm64_filename }} - asset_content_type: application/vnd.debian.binary-package \ No newline at end of file + asset_path: artifacts/$(ls artifacts/*arm64*.deb | head -1) + asset_name: $(basename $(ls artifacts/*arm64*.deb | head -1)) + asset_content_type: application/vnd.debian.binary-package + + - name: Upload ARMHF Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: artifacts/$(ls artifacts/*armhf*.deb | head -1) + asset_name: $(basename $(ls artifacts/*armhf*.deb | head -1)) + asset_content_type: application/vnd.debian.binary-package + + - name: List Generated Packages + run: | + echo "Generated packages:" + ls -la artifacts/ + echo "" + echo "Package details:" + for pkg in artifacts/*.deb; do + echo "=== $(basename $pkg) ===" + dpkg-deb -I "$pkg" | grep -E "(Package|Version|Architecture|Depends)" + echo "" + done \ No newline at end of file From 25222a5ca832e96621a44efcde673186edd8ec35 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Mon, 15 Dec 2025 23:27:47 +0530 Subject: [PATCH 15/26] Update gpio_impl --- src/ui/panel/gpio/gpio_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index 43466a8..2309516 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -239,7 +239,7 @@ class Gpio : public ComponentBase { std::string exec(const char* cmd) { std::array buffer; std::string result; - std::unique_ptr pipe(popen(cmd, "r"), pclose); + std::unique_ptr pipe(popen(cmd, "r"), pclose); if (!pipe) { return ""; } From 0c5e17615172e226a7a15d9d62e590aa98d5adbb Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Mon, 15 Dec 2025 23:45:45 +0530 Subject: [PATCH 16/26] Update workflow --- .github/workflows/armhf-release.yml | 143 +++++++++++++++++++--------- 1 file changed, 100 insertions(+), 43 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 9c09af0..f90934f 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -18,14 +18,16 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Extract Version + id: extract_version run: | VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Building version: $VERSION" - name: Setup QEMU (for ARM64) @@ -56,6 +58,7 @@ jobs: file - name: Build Package + id: build_package run: | echo "Building for ${{ matrix.arch }}" @@ -133,30 +136,52 @@ jobs: fi fi + # Verify package exists + if [ -f "package_${{ matrix.arch }}.deb" ]; then + echo "Package built successfully: package_${{ matrix.arch }}.deb" + echo "package_path=package_${{ matrix.arch }}.deb" >> $GITHUB_OUTPUT + else + echo "ERROR: No package file found!" + ls -la + exit 1 + fi + - name: Verify Package + id: verify_package run: | echo "Verifying ${{ matrix.arch }} package..." - if [ -f "package_${{ matrix.arch }}.deb" ]; then - echo "Package file: package_${{ matrix.arch }}.deb" + PACKAGE_PATH="${{ steps.build_package.outputs.package_path }}" + + if [ -f "$PACKAGE_PATH" ]; then + echo "Package file: $PACKAGE_PATH" echo "Package info:" - dpkg-deb -I "package_${{ matrix.arch }}.deb" || true + dpkg-deb -I "$PACKAGE_PATH" || true + + # Extract package metadata + PACKAGE_NAME=$(dpkg-deb -f "$PACKAGE_PATH" Package 2>/dev/null || echo "unknown-package") + PACKAGE_VERSION=$(dpkg-deb -f "$PACKAGE_PATH" Version 2>/dev/null || echo "unknown-version") - # Get actual filename for artifact - ORIG_NAME=$(basename $(dpkg-deb -f "package_${{ matrix.arch }}.deb" Package)_$(dpkg-deb -f "package_${{ matrix.arch }}.deb" Version)_${{ matrix.arch }}.deb) - echo "ORIG_NAME=$ORIG_NAME" >> $GITHUB_ENV - mv "package_${{ matrix.arch }}.deb" "$ORIG_NAME" + # Create proper filename + ORIG_FILENAME="${PACKAGE_NAME}_${PACKAGE_VERSION}_${{ matrix.arch }}.deb" + echo "Original filename will be: $ORIG_FILENAME" + + # Rename package with proper architecture + mv "$PACKAGE_PATH" "$ORIG_FILENAME" + + echo "orig_filename=$ORIG_FILENAME" >> $GITHUB_OUTPUT + echo "ORIG_FILENAME=$ORIG_FILENAME" >> $GITHUB_ENV else - echo "ERROR: No package file found for ${{ matrix.arch }}!" + echo "ERROR: Package file not found at $PACKAGE_PATH!" ls -la exit 1 fi - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.arch }}-package - path: ${{ env.ORIG_NAME }} + path: ${{ env.ORIG_FILENAME }} retention-days: 5 create-release: @@ -167,18 +192,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 - - - name: Download ARM64 Artifact - uses: actions/download-artifact@v3 - with: - name: arm64-package - path: artifacts/ + uses: actions/checkout@v4 - - name: Download ARMHF Artifact - uses: actions/download-artifact@v3 + - name: Download All Artifacts + uses: actions/download-artifact@v4 with: - name: armhf-package path: artifacts/ - name: Extract Version @@ -187,14 +205,22 @@ jobs: echo "VERSION=$VERSION" >> $GITHUB_ENV echo "Creating release for version: $VERSION" + - name: List Downloaded Artifacts + run: | + echo "Downloaded artifacts structure:" + find artifacts/ -type f -name "*.deb" | while read file; do + echo "Found: $file" + dpkg-deb -I "$file" 2>/dev/null | grep -E "(Package|Version|Architecture)" || echo "Could not read package info" + done + - name: Create Release id: create_release - uses: actions/create-release@v1 + uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref_name }} - release_name: Release ${{ github.ref_name }} + name: Release ${{ github.ref_name }} draft: false prerelease: false body: | @@ -203,35 +229,66 @@ jobs: This release contains packages for both ARM architectures: - **ARM64** (64-bit): For PocketBeagle 2 and other ARMv8/AArch64 devices - **ARMHF** (32-bit): For ARMv7 devices with hard-float ABI + + ### Download Links + - ARM64 Package: [$(basename $(find artifacts/ -name "*arm64*.deb" -o -name "*arm64-package*/*.deb" 2>/dev/null | head -1))](#) + - ARMHF Package: [$(basename $(find artifacts/ -name "*armhf*.deb" -o -name "*armhf-package*/*.deb" 2>/dev/null | head -1))](#) - - name: Upload ARM64 Asset - uses: actions/upload-release-asset@v1 + - name: Upload ARM64 Asset to Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: artifacts/$(ls artifacts/*arm64*.deb | head -1) - asset_name: $(basename $(ls artifacts/*arm64*.deb | head -1)) - asset_content_type: application/vnd.debian.binary-package + run: | + # Find the ARM64 package + ARM64_PACKAGE=$(find artifacts/ -name "*arm64*.deb" -o -path "*/arm64-package/*.deb" 2>/dev/null | head -1) + + if [ -z "$ARM64_PACKAGE" ]; then + echo "ERROR: ARM64 package not found!" + find artifacts/ -type f + exit 1 + fi + + echo "Uploading ARM64 package: $ARM64_PACKAGE" + + # Use GitHub CLI to upload the asset + gh release upload "${{ github.ref_name }}" "$ARM64_PACKAGE" \ + --repo "${{ github.repository }}" + continue-on-error: false - - name: Upload ARMHF Asset - uses: actions/upload-release-asset@v1 + - name: Upload ARMHF Asset to Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: artifacts/$(ls artifacts/*armhf*.deb | head -1) - asset_name: $(basename $(ls artifacts/*armhf*.deb | head -1)) - asset_content_type: application/vnd.debian.binary-package + run: | + # Find the ARMHF package + ARMHF_PACKAGE=$(find artifacts/ -name "*armhf*.deb" -o -path "*/armhf-package/*.deb" 2>/dev/null | head -1) + + if [ -z "$ARMHF_PACKAGE" ]; then + echo "ERROR: ARMHF package not found!" + find artifacts/ -type f + exit 1 + fi + + echo "Uploading ARMHF package: $ARMHF_PACKAGE" + + # Use GitHub CLI to upload the asset + gh release upload "${{ github.ref_name }}" "$ARMHF_PACKAGE" \ + --repo "${{ github.repository }}" + continue-on-error: false + + - name: Install GitHub CLI (if not present) + if: failure() + run: | + # Install GitHub CLI if needed for upload + type -p gh >/dev/null || curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null + sudo apt update + sudo apt install -y gh - name: List Generated Packages run: | echo "Generated packages:" - ls -la artifacts/ - echo "" - echo "Package details:" - for pkg in artifacts/*.deb; do - echo "=== $(basename $pkg) ===" - dpkg-deb -I "$pkg" | grep -E "(Package|Version|Architecture|Depends)" + find artifacts/ -name "*.deb" -type f | while read pkg; do + echo "=== $(basename "$pkg") ===" + dpkg-deb -I "$pkg" 2>/dev/null | grep -E "(Package|Version|Architecture|Depends|Installed-Size)" || echo "Could not read package info" + echo "Path: $pkg" echo "" done \ No newline at end of file From 3544f44aa7ad66e618c8de1077b584914dcb9033 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Tue, 16 Dec 2025 01:20:01 +0530 Subject: [PATCH 17/26] Update cross compiler dependencies --- .github/workflows/armhf-release.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index f90934f..cf36a92 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -43,8 +43,22 @@ jobs: - name: Install Cross-Compiler Dependencies (for ARMHF) if: matrix.arch == 'armhf' run: | + # Enable ARMHF architecture sudo dpkg --add-architecture armhf + + # Add the ports repository which contains ARMHF packages + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + + # Add ARMHF key sudo apt-get update + sudo apt-get install -y debian-archive-keyring ubuntu-keyring + + # Update package lists with new sources + sudo apt-get update + + # Install cross-compiler and libraries sudo apt-get install -y \ gcc-12-arm-linux-gnueabihf \ g++-12-arm-linux-gnueabihf \ @@ -55,7 +69,8 @@ jobs: pkg-config \ debhelper \ dh-make \ - file + file \ + git - name: Build Package id: build_package From 3ab8e4a86237d11fc66030faa3271bd0384f8c2b Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Tue, 16 Dec 2025 01:25:12 +0530 Subject: [PATCH 18/26] WIP --- .github/workflows/armhf-release.yml | 378 +++++++++++----------------- 1 file changed, 146 insertions(+), 232 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index cf36a92..2378d5e 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -5,231 +5,190 @@ on: tags: - 'v*' -env: - BUILD_TYPE: Release - jobs: - build-arm-packages: - name: Build ARM Packages + build-packages: + name: Build ${{ matrix.arch }} Package runs-on: ubuntu-22.04 strategy: matrix: arch: [arm64, armhf] + include: + - arch: arm64 + docker_platform: linux/arm64 + deb_arch: arm64 + cpu_flags: "-mcpu=cortex-a53 -mtune=cortex-a53" + - arch: armhf + docker_platform: linux/arm + deb_arch: armhf + cpu_flags: "-mcpu=cortex-a8 -mtune=cortex-a8" steps: - name: Checkout uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Extract Version - id: extract_version + id: version run: | VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') echo "VERSION=$VERSION" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Building version: $VERSION" - - - name: Setup QEMU (for ARM64) - if: matrix.arch == 'arm64' + + - name: Setup QEMU uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - + - name: Setup Buildx - if: matrix.arch == 'arm64' uses: docker/setup-buildx-action@v3 - - - name: Install Cross-Compiler Dependencies (for ARMHF) - if: matrix.arch == 'armhf' + + - name: Build with Docker run: | - # Enable ARMHF architecture - sudo dpkg --add-architecture armhf + echo "Building for ${{ matrix.arch }}" - # Add the ports repository which contains ARMHF packages - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse" | sudo tee /etc/apt/sources.list.d/armhf.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list - echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/armhf.list + # Create a Dockerfile + cat > Dockerfile.build << 'DOCKERFILE' + FROM ubuntu:22.04 - # Add ARMHF key - sudo apt-get update - sudo apt-get install -y debian-archive-keyring ubuntu-keyring + ARG VERSION + ARG CPU_FLAGS + ARG DEB_ARCH + ENV DEBIAN_FRONTEND=noninteractive - # Update package lists with new sources - sudo apt-get update + RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + pkg-config \ + libnm-dev \ + libglib2.0-dev \ + debhelper \ + dh-make \ + git \ + file \ + && rm -rf /var/lib/apt/lists/* - # Install cross-compiler and libraries - sudo apt-get install -y \ - gcc-12-arm-linux-gnueabihf \ - g++-12-arm-linux-gnueabihf \ - libnm-dev:armhf \ - libglib2.0-dev:armhf \ - cmake \ - build-essential \ - pkg-config \ - debhelper \ - dh-make \ - file \ - git - - - name: Build Package - id: build_package - run: | - echo "Building for ${{ matrix.arch }}" + WORKDIR /build + COPY . . - if [ "${{ matrix.arch }}" = "arm64" ]; then - # Build ARM64 using Docker/QEMU emulation - echo "Building ARM64 package using Docker" - - cat > Dockerfile.build << 'EOF' - FROM ubuntu:22.04 - - ENV DEBIAN_FRONTEND=noninteractive - - RUN apt-get update && apt-get install -y \ - build-essential \ - cmake \ - pkg-config \ - libnm-dev \ - libglib2.0-dev \ - debhelper \ - dh-make \ - git \ - file \ - && rm -rf /var/lib/apt/lists/* - - WORKDIR /build - COPY . . - - RUN mkdir -p build && cd build && \ - cmake .. \ - -DCMAKE_C_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ - -DCMAKE_CXX_FLAGS="-mcpu=cortex-a53 -mtune=cortex-a53 -O2 -pipe" \ - -DARCHITECTURE="arm64" \ - -DGIT_VERSION="${{ env.VERSION }}" && \ - make -j$(nproc) && \ - cpack -G DEB -D CPACK_DEBIAN_PACKAGE_ARCHITECTURE=arm64 - EOF - - docker buildx build \ - --platform linux/arm64 \ - --tag arm64-builder \ - --load \ - -f Dockerfile.build \ - . - - docker create --name builder arm64-builder - docker cp builder:/build/build/ ./ - docker rm builder - - # Find and rename the generated .deb file - DEB_FILE=$(find build -name "*.deb" -type f | head -1) - if [ -n "$DEB_FILE" ]; then - mv "$DEB_FILE" "package_${{ matrix.arch }}.deb" - fi - - else - # Build ARMHF using cross-compiler - echo "Building ARMHF package using cross-compiler" - - mkdir -p build_armhf - cd build_armhf - - cmake .. \ - -DCMAKE_CXX_COMPILER=$(which arm-linux-gnueabihf-g++-12) \ - -DCMAKE_C_COMPILER=$(which arm-linux-gnueabihf-gcc-12) \ - -DARCHITECTURE="armhf" \ - -DGIT_VERSION="${{ env.VERSION }}" - - make -j$(nproc) - make package - - # Find and rename the generated .deb file - DEB_FILE=$(find . -name "*armhf.deb" -type f | head -1) - if [ -n "$DEB_FILE" ]; then - mv "$DEB_FILE" "../package_${{ matrix.arch }}.deb" - fi - fi - - # Verify package exists - if [ -f "package_${{ matrix.arch }}.deb" ]; then - echo "Package built successfully: package_${{ matrix.arch }}.deb" - echo "package_path=package_${{ matrix.arch }}.deb" >> $GITHUB_OUTPUT + RUN mkdir -p build && cd build && \ + cmake .. \ + -DCMAKE_C_FLAGS="$CPU_FLAGS -O2 -pipe" \ + -DCMAKE_CXX_FLAGS="$CPU_FLAGS -O2 -pipe" \ + -DARCHITECTURE="$DEB_ARCH" \ + -DGIT_VERSION="$VERSION" && \ + make -j$(nproc) && \ + cpack -G DEB -D CPACK_DEBIAN_PACKAGE_ARCHITECTURE=$DEB_ARCH + DOCKERFILE + + echo "Building Docker image..." + docker buildx build \ + --platform ${{ matrix.docker_platform }} \ + --tag ${{ matrix.arch }}-builder \ + --build-arg VERSION="${{ env.VERSION }}" \ + --build-arg CPU_FLAGS="${{ matrix.cpu_flags }}" \ + --build-arg DEB_ARCH="${{ matrix.deb_arch }}" \ + --load \ + -f Dockerfile.build \ + . + + echo "Extracting package from container..." + docker create --name builder ${{ matrix.arch }}-builder + docker cp builder:/build/build/ ./ + docker rm builder + + # Find and copy the package + DEB_FILE=$(find build -name "*.deb" -type f | head -1) + if [ -n "$DEB_FILE" ]; then + # Extract package info for better naming + PKG_NAME=$(basename "$DEB_FILE") + mv "$DEB_FILE" "package_${{ matrix.arch }}.deb" + echo "Package created: package_${{ matrix.arch }}.deb" + ls -la "package_${{ matrix.arch }}.deb" + echo "package_filename=package_${{ matrix.arch }}.deb" >> $GITHUB_ENV + echo "original_pkg_name=$PKG_NAME" >> $GITHUB_ENV else - echo "ERROR: No package file found!" - ls -la + echo "ERROR: No .deb file found!" + find . -name "*.deb" -type f exit 1 fi - + - name: Verify Package - id: verify_package run: | - echo "Verifying ${{ matrix.arch }} package..." - - PACKAGE_PATH="${{ steps.build_package.outputs.package_path }}" - - if [ -f "$PACKAGE_PATH" ]; then - echo "Package file: $PACKAGE_PATH" + echo "Verifying package..." + if [ -f "package_${{ matrix.arch }}.deb" ]; then echo "Package info:" - dpkg-deb -I "$PACKAGE_PATH" || true - - # Extract package metadata - PACKAGE_NAME=$(dpkg-deb -f "$PACKAGE_PATH" Package 2>/dev/null || echo "unknown-package") - PACKAGE_VERSION=$(dpkg-deb -f "$PACKAGE_PATH" Version 2>/dev/null || echo "unknown-version") - - # Create proper filename - ORIG_FILENAME="${PACKAGE_NAME}_${PACKAGE_VERSION}_${{ matrix.arch }}.deb" - echo "Original filename will be: $ORIG_FILENAME" - - # Rename package with proper architecture - mv "$PACKAGE_PATH" "$ORIG_FILENAME" - - echo "orig_filename=$ORIG_FILENAME" >> $GITHUB_OUTPUT - echo "ORIG_FILENAME=$ORIG_FILENAME" >> $GITHUB_ENV + dpkg-deb -I "package_${{ matrix.arch }}.deb" || true + echo "" + echo "Package contents:" + dpkg-deb -c "package_${{ matrix.arch }}.deb" | head -20 else - echo "ERROR: Package file not found at $PACKAGE_PATH!" - ls -la + echo "ERROR: Package file not found!" exit 1 fi - + - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.arch }}-package - path: ${{ env.ORIG_FILENAME }} + path: package_${{ matrix.arch }}.deb retention-days: 5 create-release: name: Create Release and Upload Assets runs-on: ubuntu-22.04 - needs: build-arm-packages + needs: build-packages if: success() - + steps: - name: Checkout uses: actions/checkout@v4 - + - name: Download All Artifacts uses: actions/download-artifact@v4 with: path: artifacts/ - - - name: Extract Version - run: | - VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') - echo "VERSION=$VERSION" >> $GITHUB_ENV - echo "Creating release for version: $VERSION" - - - name: List Downloaded Artifacts + pattern: '*' + merge-multiple: true + + - name: List Downloaded Files run: | - echo "Downloaded artifacts structure:" + echo "Downloaded artifacts:" find artifacts/ -type f -name "*.deb" | while read file; do echo "Found: $file" dpkg-deb -I "$file" 2>/dev/null | grep -E "(Package|Version|Architecture)" || echo "Could not read package info" done - - - name: Create Release - id: create_release + + - name: Extract Version + run: | + VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Find Package Files + id: find_packages + run: | + # Find all .deb files in artifacts + ARM64_PKG=$(find artifacts/ -name "*arm64*.deb" -o -name "*package_arm64.deb" -o -path "*/arm64-package/*.deb" | head -1) + ARMHF_PKG=$(find artifacts/ -name "*armhf*.deb" -o -name "*package_armhf.deb" -o -path "*/armhf-package/*.deb" | head -1) + + if [ -n "$ARM64_PKG" ]; then + ARM64_BASENAME=$(basename "$ARM64_PKG") + echo "arm64_package=$ARM64_PKG" >> $GITHUB_OUTPUT + echo "arm64_basename=$ARM64_BASENAME" >> $GITHUB_OUTPUT + echo "Found ARM64 package: $ARM64_PKG" + else + echo "ERROR: ARM64 package not found!" + find artifacts/ -type f + fi + + if [ -n "$ARMHF_PKG" ]; then + ARMHF_BASENAME=$(basename "$ARMHF_PKG") + echo "armhf_package=$ARMHF_PKG" >> $GITHUB_OUTPUT + echo "armhf_basename=$ARMHF_BASENAME" >> $GITHUB_OUTPUT + echo "Found ARMHF package: $ARMHF_PKG" + else + echo "ERROR: ARMHF package not found!" + find artifacts/ -type f + fi + + - name: Create Release with Assets uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -239,71 +198,26 @@ jobs: draft: false prerelease: false body: | - ARM Cross-Platform Release + ARM Cross-Platform Release v${{ env.VERSION }} - This release contains packages for both ARM architectures: + This release contains Debian packages for both ARM architectures: - **ARM64** (64-bit): For PocketBeagle 2 and other ARMv8/AArch64 devices - **ARMHF** (32-bit): For ARMv7 devices with hard-float ABI - ### Download Links - - ARM64 Package: [$(basename $(find artifacts/ -name "*arm64*.deb" -o -name "*arm64-package*/*.deb" 2>/dev/null | head -1))](#) - - ARMHF Package: [$(basename $(find artifacts/ -name "*armhf*.deb" -o -name "*armhf-package*/*.deb" 2>/dev/null | head -1))](#) - - - name: Upload ARM64 Asset to Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Find the ARM64 package - ARM64_PACKAGE=$(find artifacts/ -name "*arm64*.deb" -o -path "*/arm64-package/*.deb" 2>/dev/null | head -1) - - if [ -z "$ARM64_PACKAGE" ]; then - echo "ERROR: ARM64 package not found!" - find artifacts/ -type f - exit 1 - fi - - echo "Uploading ARM64 package: $ARM64_PACKAGE" - - # Use GitHub CLI to upload the asset - gh release upload "${{ github.ref_name }}" "$ARM64_PACKAGE" \ - --repo "${{ github.repository }}" - continue-on-error: false - - - name: Upload ARMHF Asset to Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Find the ARMHF package - ARMHF_PACKAGE=$(find artifacts/ -name "*armhf*.deb" -o -path "*/armhf-package/*.deb" 2>/dev/null | head -1) - - if [ -z "$ARMHF_PACKAGE" ]; then - echo "ERROR: ARMHF package not found!" - find artifacts/ -type f - exit 1 - fi - - echo "Uploading ARMHF package: $ARMHF_PACKAGE" - - # Use GitHub CLI to upload the asset - gh release upload "${{ github.ref_name }}" "$ARMHF_PACKAGE" \ - --repo "${{ github.repository }}" - continue-on-error: false - - - name: Install GitHub CLI (if not present) - if: failure() - run: | - # Install GitHub CLI if needed for upload - type -p gh >/dev/null || curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - sudo apt update - sudo apt install -y gh - - - name: List Generated Packages + ### Installation + ```bash + # ARM64 devices + sudo dpkg -i ${{ steps.find_packages.outputs.arm64_basename }} + + # ARMHF devices + sudo dpkg -i ${{ steps.find_packages.outputs.armhf_basename }} + ``` + files: | + ${{ steps.find_packages.outputs.arm64_package }} + ${{ steps.find_packages.outputs.armhf_package }} + + - name: Verify Release Creation run: | - echo "Generated packages:" - find artifacts/ -name "*.deb" -type f | while read pkg; do - echo "=== $(basename "$pkg") ===" - dpkg-deb -I "$pkg" 2>/dev/null | grep -E "(Package|Version|Architecture|Depends|Installed-Size)" || echo "Could not read package info" - echo "Path: $pkg" - echo "" - done \ No newline at end of file + echo "Release created successfully!" + echo "ARM64 package: ${{ steps.find_packages.outputs.arm64_basename }}" + echo "ARMHF package: ${{ steps.find_packages.outputs.armhf_basename }}" \ No newline at end of file From 65f2dcd26b1f443a2d40b9fbfff8433750474abc Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Wed, 17 Dec 2025 00:18:37 +0530 Subject: [PATCH 19/26] Update workflow --- .github/workflows/armhf-release.yml | 64 +++++++++++++++++++---------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index 2378d5e..ce25619 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -5,6 +5,9 @@ on: tags: - 'v*' +env: + PACKAGE_NAME: bb-config + jobs: build-packages: name: Build ${{ matrix.arch }} Package @@ -32,7 +35,7 @@ jobs: VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') echo "VERSION=$VERSION" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Building version: $VERSION" + echo "Building ${{ env.PACKAGE_NAME }} version: $VERSION" - name: Setup QEMU uses: docker/setup-qemu-action@v3 @@ -41,8 +44,14 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Build with Docker + id: build_package run: | - echo "Building for ${{ matrix.arch }}" + echo "Building ${{ env.PACKAGE_NAME }} for ${{ matrix.arch }}" + + # Create final package name + FINAL_FILENAME="${{ env.PACKAGE_NAME }}-v${{ env.VERSION }}-${{ matrix.arch }}.deb" + echo "Final package will be: $FINAL_FILENAME" + echo "final_filename=$FINAL_FILENAME" >> $GITHUB_OUTPUT # Create a Dockerfile cat > Dockerfile.build << 'DOCKERFILE' @@ -51,6 +60,7 @@ jobs: ARG VERSION ARG CPU_FLAGS ARG DEB_ARCH + ARG PACKAGE_NAME ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ @@ -85,42 +95,45 @@ jobs: --build-arg VERSION="${{ env.VERSION }}" \ --build-arg CPU_FLAGS="${{ matrix.cpu_flags }}" \ --build-arg DEB_ARCH="${{ matrix.deb_arch }}" \ + --build-arg PACKAGE_NAME="${{ env.PACKAGE_NAME }}" \ --load \ -f Dockerfile.build \ . echo "Extracting package from container..." docker create --name builder ${{ matrix.arch }}-builder - docker cp builder:/build/build/ ./ + docker cp builder:/build/build/ ./build-output/ docker rm builder - # Find and copy the package - DEB_FILE=$(find build -name "*.deb" -type f | head -1) + # Find and rename the package + DEB_FILE=$(find build-output -name "*.deb" -type f | head -1) if [ -n "$DEB_FILE" ]; then - # Extract package info for better naming - PKG_NAME=$(basename "$DEB_FILE") - mv "$DEB_FILE" "package_${{ matrix.arch }}.deb" - echo "Package created: package_${{ matrix.arch }}.deb" - ls -la "package_${{ matrix.arch }}.deb" - echo "package_filename=package_${{ matrix.arch }}.deb" >> $GITHUB_ENV - echo "original_pkg_name=$PKG_NAME" >> $GITHUB_ENV + # Get original package name and version + ORIG_NAME=$(basename "$DEB_FILE") + + # Rename to final format + mv "$DEB_FILE" "$FINAL_FILENAME" + echo "Package renamed from $ORIG_NAME to $FINAL_FILENAME" + echo "Package created: $FINAL_FILENAME" + ls -la "$FINAL_FILENAME" else echo "ERROR: No .deb file found!" - find . -name "*.deb" -type f + find build-output -type f exit 1 fi - name: Verify Package run: | - echo "Verifying package..." - if [ -f "package_${{ matrix.arch }}.deb" ]; then + FINAL_FILENAME="${{ steps.build_package.outputs.final_filename }}" + echo "Verifying package: $FINAL_FILENAME" + + if [ -f "$FINAL_FILENAME" ]; then echo "Package info:" - dpkg-deb -I "package_${{ matrix.arch }}.deb" || true + dpkg-deb -I "$FINAL_FILENAME" || true echo "" - echo "Package contents:" - dpkg-deb -c "package_${{ matrix.arch }}.deb" | head -20 + echo "Package filename verified: $FINAL_FILENAME" else - echo "ERROR: Package file not found!" + echo "ERROR: Package file '$FINAL_FILENAME' not found!" exit 1 fi @@ -128,7 +141,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ matrix.arch }}-package - path: package_${{ matrix.arch }}.deb + path: ${{ steps.build_package.outputs.final_filename }} retention-days: 5 create-release: @@ -160,13 +173,14 @@ jobs: run: | VERSION=$(echo "${{ github.ref }}" | sed 's|refs/tags/||' | sed 's/^v//') echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "PACKAGE_NAME=${{ env.PACKAGE_NAME }}" >> $GITHUB_ENV - name: Find Package Files id: find_packages run: | # Find all .deb files in artifacts - ARM64_PKG=$(find artifacts/ -name "*arm64*.deb" -o -name "*package_arm64.deb" -o -path "*/arm64-package/*.deb" | head -1) - ARMHF_PKG=$(find artifacts/ -name "*armhf*.deb" -o -name "*package_armhf.deb" -o -path "*/armhf-package/*.deb" | head -1) + ARM64_PKG=$(find artifacts/ -name "*arm64*.deb" -o -path "*/arm64-package/*.deb" | head -1) + ARMHF_PKG=$(find artifacts/ -name "*armhf*.deb" -o -path "*/armhf-package/*.deb" | head -1) if [ -n "$ARM64_PKG" ]; then ARM64_BASENAME=$(basename "$ARM64_PKG") @@ -176,6 +190,7 @@ jobs: else echo "ERROR: ARM64 package not found!" find artifacts/ -type f + exit 1 fi if [ -n "$ARMHF_PKG" ]; then @@ -186,6 +201,7 @@ jobs: else echo "ERROR: ARMHF package not found!" find artifacts/ -type f + exit 1 fi - name: Create Release with Assets @@ -212,6 +228,10 @@ jobs: # ARMHF devices sudo dpkg -i ${{ steps.find_packages.outputs.armhf_basename }} ``` + + ### Files + - `${{ steps.find_packages.outputs.arm64_basename }}` (ARM64/64-bit) + - `${{ steps.find_packages.outputs.armhf_basename }}` (ARMHF/32-bit) files: | ${{ steps.find_packages.outputs.arm64_package }} ${{ steps.find_packages.outputs.armhf_package }} From bdcb135732d8f877fd040c41a459566675a87747 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 21:31:46 +0530 Subject: [PATCH 20/26] fix(gpio): enable cross-platform GPIO detection BREAKING CHANGE: Removes PocketBeagle 2 specific mappings GPIO now works on any ARM board with proper permissions --- src/ui/panel/gpio/gpio_impl.cpp | 206 ++++++++++++++++++++++++++------ 1 file changed, 170 insertions(+), 36 deletions(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index 2309516..7d1269f 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -255,33 +255,63 @@ class GPIOImpl : public PanelBase { std::string Title() override { return "GPIO"; } private: - // Get GPIO pin information using gpioinfo + // Dynamic GPIO chip detection for any board std::vector> getGpioPins() { std::vector> pins; + // First, try to get chip info using gpioinfo std::string output = exec("gpioinfo 2>/dev/null"); + + // If gpioinfo fails, try alternative methods if (output.empty()) { - return pins; + // Try to detect GPIOs from /sys/class/gpio + return detectGpioFromSysfs(); } std::istringstream iss(output); std::string line; + std::map chip_to_base; + int current_chip = -1; - // Chip number to GPIO base mapping (from your earlier output) - std::map chip_to_base = { - {0, 512}, // gpiochip0 -> base 512 - {1, 515}, // gpiochip1 -> base 515 - {2, 539}, // gpiochip2 -> base 539 - {3, 631}, // gpiochip3 -> base 631 - {4, 683}, // gpiochip4 -> base 683 - }; + // First pass: collect chip information + while (std::getline(iss, line)) { + // Look for chip information line + if (line.find("gpiochip") != std::string::npos && + line.find("lines") != std::string::npos) { + + // Extract chip number + size_t chip_pos = line.find("gpiochip"); + if (chip_pos != std::string::npos) { + std::string chip_num_str; + for (size_t i = chip_pos + 8; i < line.size() && isdigit(line[i]); i++) { + chip_num_str += line[i]; + } + if (!chip_num_str.empty()) { + current_chip = std::stoi(chip_num_str); + } + } + + // Extract base number from the line + std::regex base_regex("\\[([0-9]+)\\s*-"); + std::smatch base_match; + if (std::regex_search(line, base_match, base_regex) && base_match.size() > 1) { + int base = std::stoi(base_match[1]); + chip_to_base[current_chip] = base; + } + continue; + } + } - int current_chip = -1; + // Second pass: collect GPIO pins + iss.clear(); + iss.str(output); + current_chip = -1; while (std::getline(iss, line)) { // Check for chip header - if (line.find("gpiochip") != std::string::npos) { - // Extract chip number + if (line.find("gpiochip") != std::string::npos && + line.find("lines") != std::string::npos) { + // Extract chip number again size_t chip_pos = line.find("gpiochip"); if (chip_pos != std::string::npos) { std::string chip_num_str; @@ -295,7 +325,7 @@ class GPIOImpl : public PanelBase { continue; } - // Check for pin line + // Check for pin line with a label if (line.find("line") != std::string::npos && current_chip >= 0 && chip_to_base.find(current_chip) != chip_to_base.end()) { @@ -325,16 +355,46 @@ class GPIOImpl : public PanelBase { } } - // Check if it's a P1/P2 pin or USR_LED - if (!label.empty() && - (label.find("P1.") != std::string::npos || - label.find("P2.") != std::string::npos || - label.find("USR_LED") != std::string::npos)) { - + // Check for common GPIO labels + bool is_user_gpio = false; + + if (!label.empty()) { + // Check for common GPIO patterns + if (label.find("GPIO") != std::string::npos || + label.find("P") != std::string::npos || + label.find("USR") != std::string::npos || + label.find("LED") != std::string::npos || + label.find("BTN") != std::string::npos) { + is_user_gpio = true; + } + } else { + // If no label, check if it's a user-accessible GPIO by checking the name field + size_t name_pos = line.find("name:", colon_pos); + if (name_pos != std::string::npos) { + size_t name_end = line.find(",", name_pos); + if (name_end != std::string::npos) { + label = line.substr(name_pos + 5, name_end - name_pos - 5); + label.erase(0, label.find_first_not_of(" \t")); + label.erase(label.find_last_not_of(" \t") + 1); + + if (label.find("GPIO") != std::string::npos || + label.find("P") != std::string::npos) { + is_user_gpio = true; + } + } + } + } + + if (is_user_gpio) { // Calculate GPIO number int base = chip_to_base[current_chip]; int gpio_num = base + line_num; + // Use label or create generic one + if (label.empty()) { + label = "GPIO_" + std::to_string(gpio_num); + } + pins.push_back({gpio_num, label}); } } @@ -346,6 +406,51 @@ class GPIOImpl : public PanelBase { return pins; } + // Fallback GPIO detection from /sys/class/gpio + std::vector> detectGpioFromSysfs() { + std::vector> pins; + + // Check if /sys/class/gpio exists + if (!std::filesystem::exists("/sys/class/gpio")) { + return pins; + } + + // Look for already exported GPIOs + for (const auto& entry : std::filesystem::directory_iterator("/sys/class/gpio")) { + std::string entry_name = entry.path().filename().string(); + + if (entry_name.find("gpio") == 0 && entry_name != "gpiochip") { + // Extract GPIO number + std::string gpio_num_str = entry_name.substr(4); + + try { + int gpio_num = std::stoi(gpio_num_str); + + // Check if it's a valid GPIO (not a chip) + std::string label_path = entry.path().string() + "/label"; + std::string label = "GPIO_" + gpio_num_str; + + if (std::filesystem::exists(label_path)) { + std::ifstream label_file(label_path); + if (label_file.is_open()) { + std::getline(label_file, label); + if (label.empty()) { + label = "GPIO_" + gpio_num_str; + } + } + } + + pins.push_back({gpio_num, label}); + } catch (...) { + // Skip if not a number + continue; + } + } + } + + return pins; + } + // Export a GPIO if not already exported bool exportGpio(int gpio_num) { std::string gpio_path = "/sys/class/gpio/gpio" + std::to_string(gpio_num); @@ -370,22 +475,48 @@ class GPIOImpl : public PanelBase { return false; } + // Try to export common GPIOs for testing + void tryExportCommonGpios() { + // Try exporting some common GPIO numbers for testing + std::vector common_gpios = {2, 3, 4, 17, 27, 22, 10, 9, 11, 0, 5, 6, 13, 19, 26, 14, 15, 18, 23, 24, 25, 8, 7, 1, 12, 16, 20, 21}; + + for (int gpio : common_gpios) { + exportGpio(gpio); + usleep(10000); // 10ms between exports + } + } + void BuildUI() { - // Get list of GPIO pins from gpioinfo + // First, try exporting some common GPIOs for testing + tryExportCommonGpios(); + + // Get list of GPIO pins auto gpio_pins = getGpioPins(); + // If no pins found, show all available GPIOs from 0-1023 + if (gpio_pins.empty()) { + for (int i = 0; i < 1024; i++) { + if (exportGpio(i)) { + std::string label = "GPIO_" + std::to_string(i); + pins.push_back({i, label}); + } + } + } else { + pins = gpio_pins; + } + MenuOption menuOpt; menuOpt.on_enter = [&] { tab = 1; }; gpio_menu = Menu(&gpio_names, &selected, menuOpt); gpio_individual = Container::Vertical({}, &selected); - if (!gpio_pins.empty()) { - // Process pins from gpioinfo - for (const auto& pin : gpio_pins) { + if (!pins.empty()) { + // Process detected pins + for (const auto& pin : pins) { int gpio_num = pin.first; std::string label = pin.second; - // Try to export the GPIO + // Try to export the GPIO (if not already) if (exportGpio(gpio_num)) { std::string gpio_num_str = std::to_string(gpio_num); auto gpio = std::make_shared(gpio_num_str, label, &tab, &selected, &limit); @@ -399,9 +530,9 @@ class GPIOImpl : public PanelBase { // If no pins found, show error message if (children_.empty()) { error_message_ = "No GPIO pins found. Make sure:\n" - "1. gpiod is installed (sudo apt-get install gpiod)\n" - "2. Run with sudo privileges\n" - "3. GPIOs are accessible"; + "1. Run with sudo privileges\n" + "2. GPIOs are accessible\n" + "3. Check board compatibility"; } Add(Container::Tab( @@ -425,13 +556,15 @@ class GPIOImpl : public PanelBase { text("No GPIO pins found."), text(""), text("Possible issues:"), - text("1. gpiod not installed - run: sudo apt-get install gpiod"), - text("2. Need sudo privileges - run program with sudo"), - text("3. GPIOs not exported - run export script"), + text("1. Need sudo privileges - run program with sudo"), + text("2. Board not detected - trying common GPIOs"), + text(""), + text("Trying to export common GPIOs..."), + separator(), + text("Manually export GPIOs:"), + text(" echo > /sys/class/gpio/export"), text(""), - text("Try running:"), - text(" sudo ./export_beaglebone_pins.sh"), - text(" sudo gpioinfo") + text("Example: sudo echo 17 > /sys/class/gpio/export") }) | center | flex); } @@ -452,14 +585,15 @@ class GPIOImpl : public PanelBase { text("Available GPIOs: 0"), text(""), text("No GPIO pins detected."), - text("Try running with sudo or check installation.") + text("Try running with sudo or check board compatibility.") }) | center | flex); } - return window(text("GPIO Menu - " + std::to_string(children_.size()) + " pins"), + return window(text("GPIO Menu - " + std::to_string(children_.size()) + " pins detected"), gpio_menu->Render() | vscroll_indicator | frame | flex); } + std::vector> pins; std::vector> children_; std::vector gpio_names; Component gpio_menu; From 3814c381ad1e6284fd71cefca48a14ae68090c7a Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 23:24:18 +0530 Subject: [PATCH 21/26] Update workflow --- .github/workflows/armhf-release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index ce25619..ebe0dad 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -53,7 +53,7 @@ jobs: echo "Final package will be: $FINAL_FILENAME" echo "final_filename=$FINAL_FILENAME" >> $GITHUB_OUTPUT - # Create a Dockerfile + # Create a Dockerfile with retry logic cat > Dockerfile.build << 'DOCKERFILE' FROM ubuntu:22.04 @@ -63,7 +63,13 @@ jobs: ARG PACKAGE_NAME ENV DEBIAN_FRONTEND=noninteractive - RUN apt-get update && apt-get install -y \ + # Update repositories with retry + RUN for i in 1 2 3; do \ + apt-get update && break || sleep 5; \ + done + + # Install dependencies with minimal flags + RUN apt-get install -y --no-install-recommends \ build-essential \ cmake \ pkg-config \ @@ -73,6 +79,7 @@ jobs: dh-make \ git \ file \ + ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /build From 27df06981f3d76c4a40a905eecfc95dadb87b322 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 23:27:30 +0530 Subject: [PATCH 22/26] WIP --- .github/workflows/armhf-release.yml | 11 ++---- .github/workflows/pull_request_build.yml | 43 ++++++++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/.github/workflows/armhf-release.yml b/.github/workflows/armhf-release.yml index ebe0dad..ce25619 100644 --- a/.github/workflows/armhf-release.yml +++ b/.github/workflows/armhf-release.yml @@ -53,7 +53,7 @@ jobs: echo "Final package will be: $FINAL_FILENAME" echo "final_filename=$FINAL_FILENAME" >> $GITHUB_OUTPUT - # Create a Dockerfile with retry logic + # Create a Dockerfile cat > Dockerfile.build << 'DOCKERFILE' FROM ubuntu:22.04 @@ -63,13 +63,7 @@ jobs: ARG PACKAGE_NAME ENV DEBIAN_FRONTEND=noninteractive - # Update repositories with retry - RUN for i in 1 2 3; do \ - apt-get update && break || sleep 5; \ - done - - # Install dependencies with minimal flags - RUN apt-get install -y --no-install-recommends \ + RUN apt-get update && apt-get install -y \ build-essential \ cmake \ pkg-config \ @@ -79,7 +73,6 @@ jobs: dh-make \ git \ file \ - ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /build diff --git a/.github/workflows/pull_request_build.yml b/.github/workflows/pull_request_build.yml index 904de2a..3ee4d9d 100644 --- a/.github/workflows/pull_request_build.yml +++ b/.github/workflows/pull_request_build.yml @@ -7,21 +7,36 @@ on: - main jobs: - armhf: - name: Test build - runs-on: ubuntu-latest + test-build: + name: Test Build + runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 - - name: Install Deps + uses: actions/checkout@v4 + + - name: Setup Docker + uses: docker/setup-qemu-action@v3 + + - name: Build with Docker run: | - sudo apt install gcc-12 g++-12 libnm-dev libglib2.0-dev -y - - name: Build - run: | - cd ${{ github.workspace }} - mkdir build - cd build - cmake .. -DCMAKE_CXX_COMPILER=$(which g++-12) \ - -DCMAKE_C_COMPILER=$(which gcc-12) - make -j$(nproc) + echo "Running test build in Docker..." + + # Build and test in Docker container + docker run --rm \ + -v "$(pwd):/build" \ + -w /build \ + ubuntu:22.04 \ + /bin/bash -c " + apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + pkg-config \ + libnm-dev \ + libglib2.0-dev \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p build && cd build \ + && cmake .. \ + && make -j\$(nproc) \ + && echo 'Test build successful!'" \ No newline at end of file From 6a8da1b49535dbf93af299050c67f38d2446e7ef Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 23:30:03 +0530 Subject: [PATCH 23/26] WIP --- .github/workflows/pull_request_build.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pull_request_build.yml b/.github/workflows/pull_request_build.yml index 3ee4d9d..10f853b 100644 --- a/.github/workflows/pull_request_build.yml +++ b/.github/workflows/pull_request_build.yml @@ -15,14 +15,10 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Docker - uses: docker/setup-qemu-action@v3 - - name: Build with Docker run: | echo "Running test build in Docker..." - # Build and test in Docker container docker run --rm \ -v "$(pwd):/build" \ -w /build \ @@ -35,8 +31,9 @@ jobs: pkg-config \ libnm-dev \ libglib2.0-dev \ + git \ + ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p build && cd build \ && cmake .. \ - && make -j\$(nproc) \ - && echo 'Test build successful!'" \ No newline at end of file + && make -j\$(nproc)" \ No newline at end of file From 6ac5ada167242ee3ce42c925901bbad39624bfaa Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 23:31:56 +0530 Subject: [PATCH 24/26] WIP --- .github/workflows/pull_request_build.yml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/.github/workflows/pull_request_build.yml b/.github/workflows/pull_request_build.yml index 10f853b..0f83494 100644 --- a/.github/workflows/pull_request_build.yml +++ b/.github/workflows/pull_request_build.yml @@ -17,23 +17,8 @@ jobs: - name: Build with Docker run: | - echo "Running test build in Docker..." - docker run --rm \ -v "$(pwd):/build" \ -w /build \ ubuntu:22.04 \ - /bin/bash -c " - apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - pkg-config \ - libnm-dev \ - libglib2.0-dev \ - git \ - ca-certificates \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir -p build && cd build \ - && cmake .. \ - && make -j\$(nproc)" \ No newline at end of file + bash -c "apt-get update && apt-get install -y --no-install-recommends build-essential cmake pkg-config libnm-dev libglib2.0-dev git ca-certificates && rm -rf /var/lib/apt/lists/* && mkdir -p build && cd build && cmake .. && make -j\$(nproc)" \ No newline at end of file From ce6de3968e8033e3ea97d48e2a4176f74d02d967 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Sun, 4 Jan 2026 23:42:12 +0530 Subject: [PATCH 25/26] WIP --- src/ui/panel/gpio/gpio_impl.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index 7d1269f..9d7f65e 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -257,7 +257,7 @@ class GPIOImpl : public PanelBase { private: // Dynamic GPIO chip detection for any board std::vector> getGpioPins() { - std::vector> pins; + std::vector> detected_pins; // First, try to get chip info using gpioinfo std::string output = exec("gpioinfo 2>/dev/null"); @@ -395,7 +395,7 @@ class GPIOImpl : public PanelBase { label = "GPIO_" + std::to_string(gpio_num); } - pins.push_back({gpio_num, label}); + detected_pins.push_back({gpio_num, label}); } } } @@ -403,16 +403,16 @@ class GPIOImpl : public PanelBase { } } - return pins; + return detected_pins; } // Fallback GPIO detection from /sys/class/gpio std::vector> detectGpioFromSysfs() { - std::vector> pins; + std::vector> sysfs_pins; // Check if /sys/class/gpio exists if (!std::filesystem::exists("/sys/class/gpio")) { - return pins; + return sysfs_pins; } // Look for already exported GPIOs @@ -440,7 +440,7 @@ class GPIOImpl : public PanelBase { } } - pins.push_back({gpio_num, label}); + sysfs_pins.push_back({gpio_num, label}); } catch (...) { // Skip if not a number continue; @@ -448,7 +448,7 @@ class GPIOImpl : public PanelBase { } } - return pins; + return sysfs_pins; } // Export a GPIO if not already exported From 627796c7708c6fc505e018e19c619ea7577e7ad1 Mon Sep 17 00:00:00 2001 From: Aman Maheshwari Date: Wed, 7 Jan 2026 23:09:43 +0530 Subject: [PATCH 26/26] Update gpio --- src/ui/panel/gpio/gpio_impl.cpp | 404 ++++++++++++++++---------------- 1 file changed, 207 insertions(+), 197 deletions(-) diff --git a/src/ui/panel/gpio/gpio_impl.cpp b/src/ui/panel/gpio/gpio_impl.cpp index 9d7f65e..2981d8e 100644 --- a/src/ui/panel/gpio/gpio_impl.cpp +++ b/src/ui/panel/gpio/gpio_impl.cpp @@ -9,6 +9,7 @@ #include #include #include // for usleep +#include // for debug #include "ftxui/component/component.hpp" #include "ftxui/dom/elements.hpp" #include "ui/panel/panel.hpp" @@ -255,200 +256,225 @@ class GPIOImpl : public PanelBase { std::string Title() override { return "GPIO"; } private: - // Dynamic GPIO chip detection for any board + // Get GPIO pin information using gpioinfo - ONLY P pins std::vector> getGpioPins() { - std::vector> detected_pins; + std::vector> pins; - // First, try to get chip info using gpioinfo - std::string output = exec("gpioinfo 2>/dev/null"); + // First try with sudo + std::string output = exec("sudo gpioinfo 2>/dev/null"); - // If gpioinfo fails, try alternative methods + // If empty, try without sudo if (output.empty()) { - // Try to detect GPIOs from /sys/class/gpio - return detectGpioFromSysfs(); + output = exec("gpioinfo 2>/dev/null"); + } + + if (output.empty()) { + std::cerr << "ERROR: gpioinfo command failed or returned empty output\n"; + return pins; } std::istringstream iss(output); std::string line; + + // Map to store chip number to base GPIO number std::map chip_to_base; - int current_chip = -1; - // First pass: collect chip information - while (std::getline(iss, line)) { - // Look for chip information line - if (line.find("gpiochip") != std::string::npos && - line.find("lines") != std::string::npos) { - - // Extract chip number - size_t chip_pos = line.find("gpiochip"); - if (chip_pos != std::string::npos) { - std::string chip_num_str; - for (size_t i = chip_pos + 8; i < line.size() && isdigit(line[i]); i++) { - chip_num_str += line[i]; - } - if (!chip_num_str.empty()) { - current_chip = std::stoi(chip_num_str); - } - } - - // Extract base number from the line - std::regex base_regex("\\[([0-9]+)\\s*-"); - std::smatch base_match; - if (std::regex_search(line, base_match, base_regex) && base_match.size() > 1) { - int base = std::stoi(base_match[1]); - chip_to_base[current_chip] = base; + // First pass: Collect chip base numbers from /sys + for (int chip_num = 0; chip_num < 10; chip_num++) { + std::string base_path = "/sys/class/gpio/gpiochip" + std::to_string(chip_num) + "/base"; + std::ifstream base_file(base_path); + if (base_file.is_open()) { + std::string base_str; + if (std::getline(base_file, base_str)) { + try { + int base = std::stoi(base_str); + chip_to_base[chip_num] = base; + std::cerr << "DEBUG: Chip " << chip_num << " base = " << base << "\n"; + } catch (...) { + // Ignore conversion errors + } + } } - continue; - } } - // Second pass: collect GPIO pins - iss.clear(); - iss.str(output); - current_chip = -1; + int current_chip = -1; + bool reading_chip = false; + // Second pass: Parse gpioinfo output while (std::getline(iss, line)) { - // Check for chip header - if (line.find("gpiochip") != std::string::npos && - line.find("lines") != std::string::npos) { - // Extract chip number again - size_t chip_pos = line.find("gpiochip"); - if (chip_pos != std::string::npos) { - std::string chip_num_str; - for (size_t i = chip_pos + 8; i < line.size() && isdigit(line[i]); i++) { - chip_num_str += line[i]; - } - if (!chip_num_str.empty()) { - current_chip = std::stoi(chip_num_str); - } + // Trim leading/trailing whitespace + line.erase(0, line.find_first_not_of(" \t")); + line.erase(line.find_last_not_of(" \t") + 1); + + // Check for chip header + if (line.find("gpiochip") == 0) { + // Extract chip number from "gpiochipX" + std::string chip_str = line.substr(8); // Skip "gpiochip" + size_t space_pos = chip_str.find_first_of(" :"); + if (space_pos != std::string::npos) { + chip_str = chip_str.substr(0, space_pos); + } + + try { + current_chip = std::stoi(chip_str); + std::cerr << "DEBUG: Found chip " << current_chip << "\n"; + reading_chip = true; + } catch (...) { + current_chip = -1; + reading_chip = false; + } + continue; } - continue; - } - - // Check for pin line with a label - if (line.find("line") != std::string::npos && current_chip >= 0 && - chip_to_base.find(current_chip) != chip_to_base.end()) { - // Extract line number + // Skip if we're not reading a chip or line doesn't contain "line" + if (!reading_chip || line.find("line") == std::string::npos) { + continue; + } + + // Parse line: "line X:" size_t line_pos = line.find("line"); - if (line_pos != std::string::npos) { - // Find the colon after line number - size_t colon_pos = line.find(":", line_pos); - if (colon_pos != std::string::npos) { - // Get line number string (between "line" and ":") - std::string line_num_str = line.substr(line_pos + 4, colon_pos - line_pos - 4); - - // Clean up the string - line_num_str.erase(0, line_num_str.find_first_not_of(" \t")); - line_num_str.erase(line_num_str.find_last_not_of(" \t") + 1); + if (line_pos == std::string::npos) continue; + + // Extract line number + size_t num_start = line_pos + 4; + while (num_start < line.size() && (line[num_start] == ' ' || line[num_start] == '\t')) { + num_start++; + } + + size_t num_end = num_start; + while (num_end < line.size() && isdigit(line[num_end])) { + num_end++; + } + + if (num_end == num_start) continue; + + try { + int line_num = std::stoi(line.substr(num_start, num_end - num_start)); - if (!line_num_str.empty()) { - int line_num = std::stoi(line_num_str); - - // Extract label - look for text in quotes - std::string label; - size_t quote_start = line.find('\"'); - if (quote_start != std::string::npos) { + // Now look for P pin in the line + // First check in quotes + std::string pin_name = ""; + size_t quote_start = line.find('\"'); + if (quote_start != std::string::npos) { size_t quote_end = line.find('\"', quote_start + 1); if (quote_end != std::string::npos) { - label = line.substr(quote_start + 1, quote_end - quote_start - 1); - } - } - - // Check for common GPIO labels - bool is_user_gpio = false; - - if (!label.empty()) { - // Check for common GPIO patterns - if (label.find("GPIO") != std::string::npos || - label.find("P") != std::string::npos || - label.find("USR") != std::string::npos || - label.find("LED") != std::string::npos || - label.find("BTN") != std::string::npos) { - is_user_gpio = true; - } - } else { - // If no label, check if it's a user-accessible GPIO by checking the name field - size_t name_pos = line.find("name:", colon_pos); - if (name_pos != std::string::npos) { - size_t name_end = line.find(",", name_pos); - if (name_end != std::string::npos) { - label = line.substr(name_pos + 5, name_end - name_pos - 5); - label.erase(0, label.find_first_not_of(" \t")); - label.erase(label.find_last_not_of(" \t") + 1); + std::string quoted = line.substr(quote_start + 1, quote_end - quote_start - 1); - if (label.find("GPIO") != std::string::npos || - label.find("P") != std::string::npos) { - is_user_gpio = true; + // Check if quoted text starts with P followed by a digit + if (quoted.size() >= 2 && + (quoted[0] == 'P' || quoted[0] == 'p') && + isdigit(quoted[1])) { + pin_name = quoted; } - } } - } - - if (is_user_gpio) { + } + + // If not found in quotes, search entire line for P followed by digit + if (pin_name.empty()) { + // Search for P or p followed by digit + for (size_t i = 0; i < line.size(); i++) { + if ((line[i] == 'P' || line[i] == 'p') && + i + 1 < line.size() && isdigit(line[i + 1])) { + + // Extract the pin name + size_t start = i; + size_t end = i + 1; + while (end < line.size() && + (isdigit(line[end]) || line[end] == '.' || + line[end] == '_' || line[end] == '(')) { + end++; + } + + pin_name = line.substr(start, end - start); + + // Clean up trailing special characters + while (!pin_name.empty() && + (pin_name.back() == '(' || pin_name.back() == ' ' || + pin_name.back() == '\t')) { + pin_name.pop_back(); + } + + break; + } + } + } + + // If we found a P pin, add it + if (!pin_name.empty()) { // Calculate GPIO number - int base = chip_to_base[current_chip]; - int gpio_num = base + line_num; + int gpio_num = -1; - // Use label or create generic one - if (label.empty()) { - label = "GPIO_" + std::to_string(gpio_num); + if (chip_to_base.find(current_chip) != chip_to_base.end()) { + gpio_num = chip_to_base[current_chip] + line_num; + } else { + // Estimate: assume chips are numbered sequentially with 32 lines each + // This is a common pattern for many boards + gpio_num = current_chip * 32 + line_num; } - detected_pins.push_back({gpio_num, label}); - } + std::cerr << "DEBUG: Found P pin - Chip " << current_chip + << ", Line " << line_num << ", GPIO " << gpio_num + << ", Name: " << pin_name << "\n"; + + pins.push_back({gpio_num, pin_name}); } - } + + } catch (...) { + // Skip lines with conversion errors + continue; } - } } - return detected_pins; - } - - // Fallback GPIO detection from /sys/class/gpio - std::vector> detectGpioFromSysfs() { - std::vector> sysfs_pins; + // Sort by GPIO number + std::sort(pins.begin(), pins.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); + + // Remove duplicates + pins.erase(std::unique(pins.begin(), pins.end(), + [](const auto& a, const auto& b) { return a.first == b.first; }), + pins.end()); - // Check if /sys/class/gpio exists - if (!std::filesystem::exists("/sys/class/gpio")) { - return sysfs_pins; + std::cerr << "DEBUG: Total P pins found: " << pins.size() << "\n"; + for (const auto& pin : pins) { + std::cerr << " GPIO " << pin.first << ": " << pin.second << "\n"; } + return pins; + } + + // Alternative method if gpioinfo doesn't work + std::vector> getGpioPinsFallback() { + std::vector> pins; + // Look for already exported GPIOs - for (const auto& entry : std::filesystem::directory_iterator("/sys/class/gpio")) { - std::string entry_name = entry.path().filename().string(); - - if (entry_name.find("gpio") == 0 && entry_name != "gpiochip") { - // Extract GPIO number - std::string gpio_num_str = entry_name.substr(4); - - try { - int gpio_num = std::stoi(gpio_num_str); - - // Check if it's a valid GPIO (not a chip) - std::string label_path = entry.path().string() + "/label"; - std::string label = "GPIO_" + gpio_num_str; - - if (std::filesystem::exists(label_path)) { - std::ifstream label_file(label_path); - if (label_file.is_open()) { - std::getline(label_file, label); - if (label.empty()) { - label = "GPIO_" + gpio_num_str; - } + std::string cmd = "ls -d /sys/class/gpio/gpio[0-9]* 2>/dev/null"; + std::string result = exec(cmd.c_str()); + + if (!result.empty()) { + std::istringstream iss(result); + std::string gpio_path; + while (std::getline(iss, gpio_path)) { + // Extract GPIO number + size_t gpio_pos = gpio_path.find("gpio"); + if (gpio_pos != std::string::npos) { + std::string num_str; + for (size_t i = gpio_pos + 4; i < gpio_path.size() && isdigit(gpio_path[i]); i++) { + num_str += gpio_path[i]; + } + + if (!num_str.empty()) { + try { + int gpio_num = std::stoi(num_str); + pins.push_back({gpio_num, "GPIO" + num_str}); + } catch (...) { + // Skip + } + } } - } - - sysfs_pins.push_back({gpio_num, label}); - } catch (...) { - // Skip if not a number - continue; } - } } - return sysfs_pins; + return pins; } // Export a GPIO if not already exported @@ -475,34 +501,14 @@ class GPIOImpl : public PanelBase { return false; } - // Try to export common GPIOs for testing - void tryExportCommonGpios() { - // Try exporting some common GPIO numbers for testing - std::vector common_gpios = {2, 3, 4, 17, 27, 22, 10, 9, 11, 0, 5, 6, 13, 19, 26, 14, 15, 18, 23, 24, 25, 8, 7, 1, 12, 16, 20, 21}; - - for (int gpio : common_gpios) { - exportGpio(gpio); - usleep(10000); // 10ms between exports - } - } - void BuildUI() { - // First, try exporting some common GPIOs for testing - tryExportCommonGpios(); - - // Get list of GPIO pins + // Get list of GPIO pins from gpioinfo auto gpio_pins = getGpioPins(); - // If no pins found, show all available GPIOs from 0-1023 + // If no P pins found, try fallback if (gpio_pins.empty()) { - for (int i = 0; i < 1024; i++) { - if (exportGpio(i)) { - std::string label = "GPIO_" + std::to_string(i); - pins.push_back({i, label}); - } - } - } else { - pins = gpio_pins; + std::cerr << "WARNING: No P pins found with gpioinfo, trying fallback\n"; + gpio_pins = getGpioPinsFallback(); } MenuOption menuOpt; @@ -510,19 +516,21 @@ class GPIOImpl : public PanelBase { gpio_menu = Menu(&gpio_names, &selected, menuOpt); gpio_individual = Container::Vertical({}, &selected); - if (!pins.empty()) { - // Process detected pins - for (const auto& pin : pins) { + if (!gpio_pins.empty()) { + // Process pins from gpioinfo + for (const auto& pin : gpio_pins) { int gpio_num = pin.first; std::string label = pin.second; - // Try to export the GPIO (if not already) + // Try to export the GPIO if (exportGpio(gpio_num)) { std::string gpio_num_str = std::to_string(gpio_num); auto gpio = std::make_shared(gpio_num_str, label, &tab, &selected, &limit); children_.push_back(gpio); gpio_individual->Add(gpio); limit++; + } else { + std::cerr << "WARNING: Failed to export GPIO " << gpio_num << " (" << label << ")\n"; } } } @@ -530,9 +538,9 @@ class GPIOImpl : public PanelBase { // If no pins found, show error message if (children_.empty()) { error_message_ = "No GPIO pins found. Make sure:\n" - "1. Run with sudo privileges\n" - "2. GPIOs are accessible\n" - "3. Check board compatibility"; + "1. gpiod is installed (sudo apt-get install gpiod)\n" + "2. Run with sudo privileges\n" + "3. GPIOs are accessible"; } Add(Container::Tab( @@ -556,15 +564,13 @@ class GPIOImpl : public PanelBase { text("No GPIO pins found."), text(""), text("Possible issues:"), - text("1. Need sudo privileges - run program with sudo"), - text("2. Board not detected - trying common GPIOs"), + text("1. gpiod not installed - run: sudo apt-get install gpiod"), + text("2. Need sudo privileges - run program with sudo"), + text("3. GPIOs not exported"), text(""), - text("Trying to export common GPIOs..."), - separator(), - text("Manually export GPIOs:"), - text(" echo > /sys/class/gpio/export"), - text(""), - text("Example: sudo echo 17 > /sys/class/gpio/export") + text("Debug info:"), + text("Tried to find P pins from gpioinfo"), + text("Check terminal for debug output") }) | center | flex); } @@ -584,16 +590,20 @@ class GPIOImpl : public PanelBase { vbox({ text("Available GPIOs: 0"), text(""), - text("No GPIO pins detected."), - text("Try running with sudo or check board compatibility.") + text("No P pins detected."), + text("Looking for pins starting with 'P' (e.g., P8.10, P9.11)"), + text(""), + text("Check if:"), + text("1. Board has P pins"), + text("2. gpioinfo shows P pins"), + text("3. Run with: sudo gpioinfo | grep P") }) | center | flex); } - return window(text("GPIO Menu - " + std::to_string(children_.size()) + " pins detected"), + return window(text("GPIO Menu - " + std::to_string(children_.size()) + " P pins"), gpio_menu->Render() | vscroll_indicator | frame | flex); } - std::vector> pins; std::vector> children_; std::vector gpio_names; Component gpio_menu;