- Rust 73.7%
- HTML 14.9%
- C 8.9%
- Python 1.5%
- Shell 0.8%
- Other 0.2%
The v0.1.10 click update on the Gamma passed, but the watch stopped with an uncaught URLError when one GET timed out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| crates | ||
| docs | ||
| firmware | ||
| tools | ||
| web/flasher | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
Open-source Rust firmware for BM1370 Bitcoin miners
Bitaxe Gamma · NerdQAxe++ · NerdOCTAXE-γ · Stratum V1 + V2 · AxeOS-compatible API · Signed online updates
dvb-WarpAxe is a from-scratch firmware for ESP32-S3 miners with BM1370 ASICs, written in Rust. It replaces AxeOS (Bitaxe) and NerdOS (NerdQAxe) on the device and speaks their HTTP API, so dashboards, tuners and fleet tools that talk to a Bitaxe keep working — including WarpTune, the clock-and-voltage regulator of dvb-WarpPool.
It does what the stock firmware does — Stratum V2 with the pool's authority key checked, Stratum V1 over TLS, a fallback pool that hands back to the main pool — and differs where it counts for running a fleet: signed online updates the miner fetches and checks itself, one image for every board with the board found on the first start and Wi-Fi and pool taken over from the previous AxeOS/NerdOS settings, a password-protected setup hotspot when there is no network to join, a regulator and sensor layer that rejects implausible readings instead of acting on them, the web UI over the USB cable as well as over Wi-Fi, and one web UI in eight languages for the Bitaxe and the Nerd series. The device display has animated special screens (yes, a found block gets a warp jump). See Compared with the stock firmware for where it is ahead and where it is not.
The chip protocol, the chain driver and the board drivers are no_std
crates that run under cargo test against a simulated chain and a scripted
I²C bus, so most of the firmware is tested on a laptop before it touches a
miner.
Status: early (v0.1.10). It mines 24/7 on one Bitaxe Gamma and one NerdQAxe++ (Rev 6.1, on Stratum V2) under WarpTune, since 28 September on one NerdOCTAXE-γ (Rev 3.1, 6-phase regulator) and since 29 September on one NerdAxe Gaia and one BitForge Nano. Other boards have a profile but have not run it — see Supported boards before you flash.
Compared with the stock firmware
As of 2026-09-28, against ESP-Miner/AxeOS v2.15.3 and ESP-Miner-NerdQAxePlus (NerdOS) v1.1.0.1, from their source. Both move fast; corrections welcome.
| AxeOS | NerdOS | WarpAxe | |
|---|---|---|---|
| Stratum V2 (Noise, authority key, "require authentication") | yes | yes | yes |
| Stratum V1 over TLS, certificate checked | yes | yes | yes |
| Fallback pool, back to the main pool on its own | yes | yes (plus dual-pool mode) | yes |
| Update: miner fetches the release itself | no (download, then upload) | yes (from GitHub) | yes (from the release page, install on a click) |
| Update image signature-checked before flashing | no | no | yes (BIP-340, key built into the firmware) |
| Images | factory image per board version (update image shared) | one per board | one for all boards |
| Board | set in NVS at the factory | per image | found on the first start (factory NVS, read-only I²C probe) |
| Settings on an update or reinstall | kept on online update; web flasher can keep them | kept with the update's "keep settings" option | kept on online update and web-flasher reinstall; taken over from AxeOS/NerdOS when switching (Wi-Fi, pools — also AxeOS 2.15's —, hostname, clock and voltage, fans and temperature limits, display) |
| Back on after an overheat stop | yes (≥ 30 s, regulator 10 °C cooler) | not found | yes (≥ 60 s, chip and regulator 10 °C cooler; the third stop within an hour stays off) |
| Regulator fault (PMBus STATUS_WORD) | reported (power_fault), no reaction |
read once at init, logged | reported (power_fault with codes, display and web UI) and treated like an overheat stop: core voltage off, faults cleared and retried after a minute, the third within an hour stays off |
| Wi-Fi setup without a network | open hotspot (Bitaxe_XXXX), or Bluetooth |
open hotspot (Nerdaxe_XXXX) |
WPA2 hotspot, password shown only on the device display |
| Implausible sensor/regulator readings | partly ignored (fan loop) | not found | rejected before the control loops see them |
| Web UI over the USB cable | not found | not found | yes (USB network adapter, 192.168.7.1) |
| Web UI languages | English | 9 | 8 |
| Language, tests | C | C++/C | Rust; chip, chain and board drivers host-tested against a simulated chain and I²C bus |
| Supported boards | ~20 board versions | 11 boards | 3 tested (see below) |
Where the stock firmware is ahead: far more boards and years of use by a large community; AxeOS has a scoreboard, themes, the BAP accessory port and Wi-Fi setup over Bluetooth; NerdOS has two-factor login for updates, dual-pool mining, InfluxDB/Grafana export and alerts. WarpAxe is early; if you need any of that, stay with the stock firmware.
With WarpTune
WarpTune, the clock-and-voltage regulator of dvb-WarpPool, works on the stock firmware in full — it talks the AxeOS API, and WarpAxe keeps that API. The difference is what the firmware says about itself: WarpAxe reports these states explicitly, so WarpTune does not have to guess them from the power draw:
- Overheat stop:
overheat_modewhile it lasts,overheatTripsandoverheatCause(hot, a lost sensor, or a regulator fault:power, with the conditions inpowerFaultCodes). WarpTune holds during the stop, and after a hot stop takes the clock one step down (two from the second stop in an hour); a lost sensor is no reason to step down. - Chips off or the chain still coming up:
chainStoppedandchainPhase, so a chain that is powering up is not taken for a dead chip. - Fallback pool and reject reasons, as on current AxeOS.
The table on the WarpPool side lists, firmware by firmware, what WarpTune gets from AxeOS, NerdOS, ForgeOS and WarpAxe.
Screenshots
Web UI

Dashboard — chip grid and series colour, the hashrate with its share of the expected rate, efficiency, power, shares and best difficulty, the 1 h / 3 h history; below, temperature, fans and power, and the pool with the payout of a found block.

Swarm — every miner on the network, WarpAxe or stock firmware, read by your browser: the fleet's hashrate and each miner's share of it, sparklines, chip and regulator temperatures against their limits.

Settings — clock and voltage as the manufacturer's steps (Wi-Fi, hostname and time are on their own Network tab); ?oc in the address unlocks free values and the expert section (fan PID, second fan output, suggested difficulty, job interval).

Network — Wi-Fi with a list of networks found, hostname, time by NTP and time zone.

System — online update from the releases, upload, download mode for a reinstall with the web flasher, maintenance (switch the chips off without losing the device, reset overheat) and the live log.

Pool — the connection (protocol, Noise/TLS, fallback), shares with reject reasons, and who a found block pays: your share, the coinbase value and each output. Below, main and fallback pool, each Stratum V1 with optional TLS or Stratum V2 with the pool's authority key.
Device display

NerdQAxe++ (320×170 LCD) — the cockpit and three of the four pages the page key steps through (a log page follows). Block height, halving and network difficulty come from the pool's job; the BTC price line appears only if you switch it on.

Block found — stars accelerate into a warp jump, a flash, then the height with shock rings until a key is pressed.

Special screens — overheat (pulsing frame), chips off, firmware update with progress.

Setup hotspot — name and password (new at every start, example shown) on the LCD; on the OLED they take turns with the address.

Bitaxe Gamma (128×32 OLED) — hashrate large, rotating values, full-width info slides and the wordmark.
All display images are rendered from the firmware's own drawing code
(tools/display-preview) with sample values; a device's screen can be read
back at any time with GET /api/v1/display/frame.
Features
Mining
- BM1370 chain driver: enumeration, baud switch, PLL solved (not looked up) and ramped, work dispatch, nonce attribution, stale and duplicate filtering, per-chip silence watchdog.
- Stratum V2 per pool: Noise handshake (secp256k1 + EllSwift,
ChaCha20-Poly1305), extended channel, the pool's certificate checked
against its authority key (Base58Check, as pools publish it). "Require
pool authentication" is on by default: without a key, or before the clock
is set by NTP, there is no connection. The TLS switch applies to V1 only;
V2 is always encrypted. The display shows "V2" with the lock. Settings
from NerdOS (
sv2_proto,sv2_auth_pk,sv2_reqauth) are taken over on the first start. - Stratum V1 with version rolling (BIP 310),
mining.suggest_difficulty, optional TLS (esp-tls, built-in CA bundle, hostname checked). - Fallback pool: after three failed attempts on the main pool; a probe every five minutes brings it back as soon as the main pool answers.
- Block height, network difficulty and the pool's coinbase tag read from the job; a nonce at or above the network difficulty is reported as a found block.
Board
- Regulators: TPS546 (Bitaxe Gamma), TPS53647/TPS53667 (Nerd boards).
- Sensors and fans: EMC2101, EMC2302 (two outputs), TMP1075, FXL6408 GPIO expander.
- Fan PID with ESP-Miner's gains, a second output that follows the regulator temperature — or, with Link the fans, runs at the chip fan's speed for cases where every fan cools the whole board (Y-cables) — minimum speed, polarity.
- Overheat shutdown of the core voltage and a guard for a lost chip sensor (60 s blind = off). The chips start again on their own once chip and regulator are 10 °C below their limits (at least 60 s off; after a lost sensor only with real readings back); the third stop within an hour stays off until it is cleared by hand.
- Plausibility windows for every reading: a regulator that answers garbage while it powers up is reported as "no reading", never as a value a tuner could act on.
- Switch the chips off and on again from the web UI or the API; the device stays reachable.
Web UI and API
- One UI for every board, series colour and chip grid on the type plate; English, German, Spanish, French, Italian, Brazilian Portuguese, Japanese and Chinese, each reviewed by a native speaker (the device display in the six Latin-script ones).
- Dashboard and Pool page in the warp design: one hero with the hashrate, its share of the expected rate and the 1 h / 3 h history (hashrate as a two-minute average, temperature in steps of at least 0.5 °C, so counting noise does not fill the chart), then temperature, fan/power and pool instruments; live log.
- Coinbase payout of every job, as AxeOS shows it: the share of a found block that goes to your address (green from 95 %, red below), the coinbase value and its outputs, over Stratum V1 and V2.
- Swarm page for the other miners on the network — AxeOS, NerdOS,
ForgeOS or WarpAxe: fleet hashrate, power, J/TH and record difficulty,
each miner's share, a card per miner with a sparkline and its
temperatures. The browser reads every miner's
/api/system/infodirectly (every 30 s by default, not while the tab is hidden, one request per miner at a time); this miner stores only the address list. Read-only: it never changes or restarts another miner. Add miners by address or by a search of the local /24. - Tabs in the stock order: Dashboard, Swarm, Network, Pool, Settings, System; the starfield background of dvb-WarpPool.
- AxeOS/NerdOS-compatible endpoints:
/api/system/info,PATCH /api/system,/api/system/asic,/api/v2/settings, restart, OTA upload. - WarpAxe's own:
/api/v1/state,/api/v1/history,/api/v1/log, chips off/on, overheat and best-difficulty reset, Wi-Fi scan, display frame / key / demo, online update, download mode for the web flasher, the swarm list (/api/v1/swarm). - States a tuner would otherwise have to guess from the power draw are in
/api/system/info:chainStoppedandchainPhase,overheat_mode,overheatTrips(stops in the last hour),overheatCause(hot, a lost sensor or a regulator fault),overheatLatched,power_fault(AxeOS's field and wording) withpowerFaultCodes,isUsingFallbackStratum,sharesRejectedReasons, AxeOS'scoinbaseOutputs,coinbaseValueTotalSatoshisandcoinbaseValueUserSatoshis, andtemptarget(the fan target, under ESP-Miner's name) so a tuner keeps its own target above it. - Setup hotspot: with no network in the settings, or none reached within
three minutes of a start, the miner opens
WarpAxe-XXXX— WPA2, with a ten-digit password made at every start and shown only on the device display. A phone that joins it gets the Wi-Fi setup page by itself (captive portal); after saving, the miner restarts, joins the network and closes the hotspot. The log names the address behind every restart, download-mode and overheat-reset request.
Device display
- NerdQAxe++ LCD: cockpit with the last hour's hashrate, Bitcoin, device, pool and log pages, anti-aliased fonts (Space Grotesk, JetBrains Mono, Inter) pre-rendered at build time.
- Bitaxe OLED: large hashrate, rotating values, info slides, share blink.
- Special screens for block found, overheat, chips off and firmware update; display language, time zone, screen timeout.
- Optional BTC price and fee rates from mempool.space — off by default; with it off the miner talks to its pool and nothing else (plus the update check, which you can switch off too).
Updates
- Online update: the miner checks this repository's releases at start
and every hour, the web UI shows the new version and its notes (and a
pill in the header on every page), and
one click downloads, verifies (SHA-256 and the release signature: BIP-340
Schnorr with the key built into the firmware,
warpaxe.bin.sig) and installs it. A release without a signature still installs for now and is marked as unsigned; that tolerance ends once every release carries one. Nothing installs by itself: an update restarts the miner. - Downloads are tried up to three times; the log names the address that started an install, an upload or an update check, and the last install (version and signature result) is kept across the restart.
- Upload a
warpaxe.binin the web UI, orcurl --data-binary @warpaxe.bin http://<miner>/api/system/OTA— a manual upload is your own image and is not signature-checked. - The web UI and its fonts are part of the image: one file, one update.
Supported boards
| Board | ASICs | Regulator | Status |
|---|---|---|---|
| Bitaxe Gamma (601/602) | 1× BM1370 | TPS546 | runs 24/7 |
| NerdQAxe++ (every revision but Rev 7; NerdOS treats them alike) | 4× BM1370 | TPS53647 | runs 24/7 (on a Rev 6.1) |
| NerdQAxe++ Rev 7 | 4× BM1370 | TPS546 (two voltage domains) | profile from NerdOS, recognised on the bus and offered for one click; not run yet |
| NerdOCTAXE-γ Rev 3.1 | 8× BM1370 | TPS53667 (6-phase) | runs since 2026-09-28; at 700 MHz / 1210 mV the pool counts 11.59 TH/s ± 2.5 % (NerdOS: 11.71) since v0.1.9 paces work as NerdOS does (the 4-phase TPS53647 variant has not run) |
| BitForge Nano (800) | 2× BM1370 | TPS546 + INA260 | runs since 2026-09-29 (ForgeOS's 525 MHz / 1150 mV: about 2.2 TH/s at 43–45 W); offered on the first start, never taken on its own |
| Bitaxe Gamma Duo (650) | 2× BM1370 | TPS546 | profile only, not run yet |
| Bitaxe Gamma Turbo (801) | 2× BM1370 | 2× TPS546 | profile only, not run yet |
| Bitaxe Naja Duo (1201) | 2× BM1373 | 2× TPS546 (two domains) | profile only, not run yet |
| Bitaxe Gamma Hex (1300) | 6× BM1370 | 4× TPS546 (two domains) | profile only, not run yet |
| NerdAxe Gamma | 1× BM1370 | TPS546 | profile only, not run yet |
| NerdAxe Gaia | 1× BM1373 | TPS546 (12 V) | runs since 2026-09-29; at 420 MHz / 960 mV the pool counts 102 % of the expected rate, as with its stock firmware, but the core then draws 31–33 A against the regulator's 33 A limit; clock and voltage capped at 420 MHz / 970 mV |
| NerdQX (Q1370 / Q1373) | 4× BM1370 / BM1373 | TPS53647 | profile only, not run yet |
Boards marked "profile only" have pins, regulator window and limits taken from their stock firmware, but nobody has run WarpAxe on one yet. Please don't flash them unless you can recover the stock firmware over USB.
Install
First install needs a USB cable once; after that the miner sets itself up and updates itself:
- Keep a way back —
tools/flash-backup.shreads the whole flash (16 MB) over USB; or keep the stock firmware at hand (the Bitaxe and NerdQAxe web flashers put it back). - Install WarpAxe from the browser with the web flasher at
warppool.org/warpaxe (Chrome or Edge
on a computer). It writes bootloader, partition table and app and
leaves the settings partition alone, so WarpAxe reads what AxeOS or
NerdOS left there; it checks every part against the flash and restarts
the miner when it is done. The flasher serves the current release; its
image carries the same signature the online update checks. Coming from
the stock firmware, the flasher usually puts the miner into download
mode by itself; otherwise hold BOOT, press RST, release BOOT (on a miner
that already runs WarpAxe: System → Download mode). A miner that
stays dark after a cancelled install is still in download mode: take it
off power completely — power supply and USB cable — for a few
seconds. Without a browser:
warpaxe-factory.binfrom the release at offset 0 with esptool (this one starts with empty settings), or Build from source. - On the first start WarpAxe takes Wi-Fi, pools, hostname, clock and voltage, fan settings, temperature limits and display orientation from the previous firmware (not the fan PID gains, which belong to its own loop) and finds the board: from the model AxeOS stored at the factory, or from the chips that answer on the board's I²C bus (read-only probes on pins that switch nothing). A Bitaxe Gamma starts mining at once. For the Nerd boards the web UI asks once which board it is — the NerdQAxe++ and the NerdOctaxe look alike on the bus — and the chips stay off until you answer.
- Open the web UI at the miner's address — or, on boards with native USB,
at
http://192.168.7.1over the USB cable (the miner shows up as a USB network adapter). If there was no Wi-Fi to take over, or it cannot be reached, the miner opens its setup hotspot after three minutes: joinWarpAxe-XXXXwith the password on its display and choose your network.
Updates after that come from the web UI: System → Online update →
Install, or upload warpaxe.bin from the
releases page.
Every release carries warpaxe.bin (one image for all boards — the board is
configuration), warpaxe.bin.sha256 and warpaxe.bin.sig; for the first
install also warpaxe-factory.bin (bootloader, partition table and app in
one image) and web-flasher.tar.gz (the web flasher as published), with
their checksums in install.sha256. tools/verify-release.py checks an
image's signature without the Rust toolchain.
Build from source
Host crates and tests:
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo build -p warpaxe-core --target thumbv7em-none-eabihf # proves no_std
Firmware (Xtensa, ESP-IDF 5.3 via esp-idf-svc; toolchain from
espup; its export script must be
sourced first, the C code in secp256k1-sys needs xtensa-esp32s3-elf-gcc
on the PATH):
cd firmware/warpaxe
cargo build --release
espflash save-image --chip esp32s3 --flash-size 16mb \
target/xtensa-esp32s3-espidf/release/warpaxe warpaxe.bin # OTA image
espflash flash --partition-table partitions.csv \
target/xtensa-esp32s3-espidf/release/warpaxe # first install over USB
Display preview on the host (every page, special screen and OLED slide as PNG, from the firmware's own drawing code):
cargo run --release --manifest-path tools/display-preview/Cargo.toml -- /tmp/frames
for f in /tmp/frames/*.raw; do python3 tools/frame2png.py "$f" "${f%.raw}.png"; done
Fonts and the splash are generated from tools/fonts (SIL Open Font
License) and docs/brand by tools/make-fonts.py and
tools/make-splash.py; releases are published with
tools/release-firmware.sh.
Repository
| Path | What |
|---|---|
crates/core |
BM13xx wire protocol: frames, CRCs, decoders, PLL solver, register payloads, chip profiles with the init sequence as data — no_std, no alloc |
crates/chain |
the chain driver over a Uart trait — no_std, the code the firmware runs |
crates/board |
regulators, sensors, fans, fan PID, OLED, board profiles over an I2c trait — no_std, tested against a scripted bus |
crates/stratum |
Stratum V1 without sockets: messages, jobs, coinbase reading, tested against a captured WarpPool session |
crates/sv2 |
Stratum V2 client: Noise handshake, framing, mining messages, release-signature tool; tested against WarpPool's Sv2 server |
crates/sim, crates/simuart |
a simulated BM1370 chain and board with fault injection |
crates/axeos, crates/cgminer |
AxeOS- and cgminer-compatible devices on top of the simulator, for testing tuners |
crates/scenarios |
WarpTune's regulator in-process against the simulated devices (git dependency on dvb-WarpPool) |
firmware/warpaxe |
the ESP32-S3 firmware: Wi-Fi and USB networking, Stratum, miner, board, web UI, display, updates |
tools/ |
font and splash generators, display preview, flash backup, release script |
Run the simulated AxeOS device, for example to test a tuner:
cargo run --release -p warpaxe-axeos -- --port 8811 --time-scale 30
curl -s http://127.0.0.1:8811/api/system/info | jq .
curl -s -X POST -d '{"board":{"SilentVrShutdown":{"above_hz":600000000}}}' http://127.0.0.1:8811/sim/fault
Design
docs/00-Design-BM1370.md— architecture, chip profiles, PLL, simulator, findings, the transport decision (USB-NCM + USB bridge) and the firmware's operating notes;docs/01-Benefit-for-WarpTune.md— what this buys WarpTune, concretely;docs/02-Demo-WarpTune-vs-Sim-2026-09-23.txt— the first run of WarpTune against the emulator, unedited.
Short version: registers and init sequences are data, not code per chip; the PLL is solved, so the reported frequency is the real one; and the simulator exists to make field failures reproducible — including the one that started this project, a regulator that shut down silently while the stock firmware kept reporting full hashrate.
Provenance
The BM1370/BM1373 have no public datasheet. What is known comes from
reverse engineering, chiefly ESP-Miner
(GPL-3.0) and, for the Nerd boards,
ESP-Miner-NerdQAxePlus
(GPL-3.0). Every constant lifted from there says so in its doc comment;
every test vector says where it came from. The Bitcoin whitepaper served by
the firmware is Satoshi Nakamoto's bitcoin.pdf (SHA-256
b1674191…f553).
License
GPL-3.0-or-later (see LICENSE), for the reason above. The fonts
in tools/fonts are under the SIL Open Font License.