diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e060e97 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +image-factory \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..25ae5d7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:latest + +WORKDIR /app + +COPY . /app + +RUN npm install +RUN npm run build +RUN npm install --global serve +RUN ln -s /app/out out/bitaxe-web-flasher + +CMD [ "serve", "out" ] diff --git a/image-factory/.gitignore b/image-factory/.gitignore new file mode 100644 index 0000000..37465b4 --- /dev/null +++ b/image-factory/.gitignore @@ -0,0 +1,2 @@ +*.bin +firmware_data.csv \ No newline at end of file diff --git a/image-factory/Dockerfile-expressif b/image-factory/Dockerfile-expressif new file mode 100644 index 0000000..758022c --- /dev/null +++ b/image-factory/Dockerfile-expressif @@ -0,0 +1,16 @@ +ARG IDF_VERSION=v5.4 +FROM espressif/idf:${IDF_VERSION} + +RUN apt-get update && apt-get install -y \ + curl \ + gnupg \ + ca-certificates + +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + +RUN apt-get install -y nodejs=22.11.0-1nodesource1 + +RUN npm install -g @angular/cli + +ENV IDF_TARGET="esp32s3" + diff --git a/image-factory/README.md b/image-factory/README.md new file mode 100644 index 0000000..091bdce --- /dev/null +++ b/image-factory/README.md @@ -0,0 +1,52 @@ +# Build Factory Images With Docker + +build-images.sh is a script that builds the factory images with only Docker as a dependency. + +After the images are built the script runs the web flasher to allow flashing the Bitaxe + with the newly built dev images. It should open your default browser to http://localhost:3000. + +## Requirements + +Docker must be installed. https://docs.docker.com/get-started/get-docker/ + +ESP_MINER_PATH must be set to the path of the ESP-Miner project. + +```shell +export ESP_MINER_PATH=~/dev/ESP-Miner +``` + +It can be set when running the build-images.sh script. + +```shell +./image-factory/build-images.sh ESP_MINER_PATH=~/dev/ESP-Miner -t mytag +``` + +## Building Images + +The command is run from the web flasher project root `./image-factory/build-images.sh`. To build images +for all boards specify a tag. The tag defaults to `dev`. + +```shell +./image-factory/build-images.sh -t 2.4.2b +``` + +To build an image for a specific board using expressif/idf version v5.5-dev + +```shell +./image-factory/build-images.sh -e v5.5-dev -b 204 -t PR-609 +``` + + If the images were already built previously you can launch the web flasher only with + +```shell +./image-factory/build-images.sh -f +``` + +## Image Location + +This build process puts the factory images into the `image-factory` directory. The images +are named `esp-miner-factory--.bin`. The web flasher is configured to look for +these local images by loading the `firmware_data.csv` file, supplementing the existing released firmware. + +![alt text](image-1.png) + diff --git a/image-factory/build-images.sh b/image-factory/build-images.sh new file mode 100755 index 0000000..7d51e54 --- /dev/null +++ b/image-factory/build-images.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +if [ ! -d "$ESP_MINER_PATH" ]; then + echo "ESP_MINER_PATH not found: $ESP_MINER_PATH" + exit 1 +fi + +board="" +idf_version="v5.4" +flash_only=0 +tag="dev" + +function show_help() { + echo "Usage: build-images.sh [OPTIONS]" + echo "Options:" + echo " -b board: Build only board image. example: 601" + echo " -e: espressif/idf version. default: $idf_version" + echo " -f: Only launch the web flasher" + echo " -t tag: Add tag to image name esp-miner-factory--.bin. default: $tag" +} + +if [ $# -eq 0 ]; then + show_help + exit 0 +fi + +while getopts "b:e:ft:" opt; do + case "$opt" in + f) + flash_only=1 + ;; + b) board=$OPTARG + ;; + e) idf_version=$OPTARG + ;; + t) tag=$OPTARG + ;; + esac +done + +if [ $flash_only -eq 0 ]; then + echo "Building esp-miner-factory with idf version $idf_version" + docker build -t esp-miner-factory \ + --build-arg IDF_VERSION=$idf_version \ + -f image-factory/Dockerfile-expressif . + + docker run --rm -v $ESP_MINER_PATH:/project -w /project esp-miner-factory idf.py build + if [ $? -ne 0 ]; then + echo "IDF build failed, check the logs for more information" + exit 1 + fi + + if [ -z "$board" ]; then + boards="102 201 202 203 204 205 401 402 403 601" + else + boards=$board + fi + + for board in $boards; do + if [ -f "$ESP_MINER_PATH/config-$board.cvs" ]; then + # Build config.bin for $board + docker run --rm -w /project -v $ESP_MINER_PATH:/project esp-miner-factory \ + /opt/esp/idf/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py \ + generate config-${board}.cvs config.bin 0x6000 + + bin_file="esp-miner-factory-${board}-${tag}.bin" + + # Creating image for board $board to public/firmware + docker run --rm -w /project -v $ESP_MINER_PATH:/project \ + -v $PWD/image-factory:/firmware \ + esp-miner-factory \ + /project/merge_bin.sh -c /firmware/$bin_file + + # Tell webflasher about our local firmware + name="" + case "$board" in + "102") + name="Max" + ;; + "201"|"202"|"203"|"204"|"205") + name="Ultra" + ;; + "401"|"402"|"403") + name="Supra" + ;; + "601") + name="Gamma" + ;; + esac + echo "Found board: $board" + if [ -n "$name" ]; then + echo "$name,$board,$tag,firmware_local/$bin_file" >> image-factory/firmware_data.csv + echo "name: $name" + fi + fi + done +fi + +# Remove duplicates from firmware_data.csv +sort -u image-factory/firmware_data.csv -o image-factory/firmware_data.csv + +# Build webflasher image +docker build -t bitaxe-web-flasher . + +Open web browser to the local webflasher +if command -v xdg-open >/dev/null 2>&1; then + # Linux + xdg-open "http://localhost:3000" +elif command -v open >/dev/null 2>&1; then + # macOS + open "http://localhost:3000" +elif command -v start >/dev/null 2>&1; then + # Windows + start "http://localhost:3000" +fi + +# Use start the web flasher with the dev firmware in the build-docker directory +docker run --rm --name bwf \ + -v $PWD/image-factory:/app/out/firmware_local \ + -p 3000:3000 bitaxe-web-flasher diff --git a/image-factory/image-1.png b/image-factory/image-1.png new file mode 100644 index 0000000..33feb7e Binary files /dev/null and b/image-factory/image-1.png differ diff --git a/src/components/LandingHero.tsx b/src/components/LandingHero.tsx index ff86b8d..5b8d951 100644 --- a/src/components/LandingHero.tsx +++ b/src/components/LandingHero.tsx @@ -8,13 +8,15 @@ import { useTranslation } from 'react-i18next' import Header from './Header' import InstructionPanel from './InstructionPanel' import Selector from './Selector' -import device_data from './firmware_data.json' +import { FirmwareData } from '../lib/types' +import firmware_data from './firmware_data.json' import { Terminal } from '@xterm/xterm'; import '@xterm/xterm/css/xterm.css'; export default function LandingHero() { const { t } = useTranslation(); + const [device_data, setDeviceData] = useState(firmware_data) const [selectedDevice, setSelectedDevice] = useState('') const [selectedBoardVersion, setSelectedBoardVersion] = useState('') const [selectedFirmware, setSelectedFirmware] = useState('') @@ -37,6 +39,34 @@ export default function LandingHero() { const userAgent = navigator.userAgent.toLowerCase(); const isChromium = /chrome|chromium|crios|edge/i.test(userAgent); setIsChromiumBased(isChromium); + + // Released firmware data + const firmwareData = firmware_data + + // Append the local built firmware if available + fetch('/firmware_local/firmware_data.csv') + .then((response) => { + if (response.ok) { + response.text().then(data => { + const lines = data.split('\n'); + lines.map(line => { + const [device, board, version, path] = line.split(','); + + const firmwareDevice = firmwareData.devices.find(d => d.name == device); + if (!firmwareDevice) return; + + const firmwareBoard = firmwareDevice.boards.find(b => b.name == board); + if (!firmwareBoard) return; + + const existingFirmware = firmwareBoard.supported_firmware.find(f => f.version === version); + if (existingFirmware) return; + + firmwareBoard.supported_firmware.push({ version, path }); + }); + setDeviceData(firmwareData) + }) + } + }) }, []); useEffect(() => { diff --git a/src/lib/types.ts b/src/lib/types.ts index 9bb706b..37ade6b 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,2 +1,21 @@ // Add any shared types here -export type DeviceModel = 'max' | 'ultra' | 'supra' | 'gamma' | 'ultrahex' | 'suprahex'; \ No newline at end of file +export type DeviceModel = 'max' | 'ultra' | 'supra' | 'gamma' | 'ultrahex' | 'suprahex'; + +export type FirmwareData = { + devices: Device[] +} + +type Device = { + name: string + boards: Board[] +} + +type Board = { + name: string + supported_firmware: Firmware[] +} + +type Firmware = { + version: string + path: string +} \ No newline at end of file