MeshCore, on a bench

Fail it at your desk,
not on a hilltop

Forty nodes and a mountain between two radios, on your machine. Break the link on purpose and read exactly why it broke — real MeshCore firmware, a sample-accurate LoRa channel, real terrain, and a demodulator that finds out for itself.

One binary. No service to deploy, no account, nothing to configure before the first run.

Three questions

One binary, and the three people who open it

They arrive with different questions, and the tool answers all three against the same physics.

Plan a network

Where the next node should go

Coverage rasterised over real terrain and searched for the best site. Both link margins for any pair — both, because reachability is asymmetric — and the terrain cut-through that explains them. Import a live network from CoreScope, Beacon or MQTT and ask what it would do.

Develop firmware

Did my branch relay more, or less?

MeshCore's own code, not a reimplementation: routing, flood suppression, duty-cycle policing and CSMA timing are the real thing. Point meshbench dev at a checkout, run half the mesh on one build and half on another, same traffic, and diff.

Build an application

How does my app cope with a bad link?

meshbench serve exposes a node over TCP, a serial pty or Bluetooth — the real companion protocol, spoken by real firmware. Your app cannot tell it from a radio on a desk, and you can put forty nodes and a hill between it and the far end.

Why the physics matters

The channel decides nothing

Most mesh simulators answer did the packet arrive from a link-budget rule. That tells you nothing about the case that actually matters: a marginal link, two nodes transmitting at once, a hill in the way.

It sums waveforms and adds noise.

Path loss over real terrain, thermal noise, and then every receiver's demodulator finds out for itself. Capture effect, partial collisions and sensitivity are emergent — nobody wrote them down as rules, which is why the failure you are chasing can happen here at all.

The receive chain, in full
dechirpGraydiagonal deinterleave Hamming FECdewhitenheader CRC payload CRC

Airtime matches the firmware's own getEstAirtimeFor(). Its CSMA timing is built on that number, and a channel that disagrees desynchronises silently.

What you get

Every answer, with its working shown

Why a link missedTerrain cut-through with the Fresnel zone and each diffracting edge's own loss, in both directions.
What the air looked likeWaterfall, IQ, and a dechirped symbol view showing which of two colliding frames captured.
Coverage and planningLink budgets rasterised over terrain, combined across a fleet, and searched for the next site.
Real boardsPublished .uf2 and .bin images under QEMU and Renode, with a matrix of what has been watched happening.
Firmware A/BHalf the repeaters on one build, half on another, same traffic, and diff.
Your app against a meshA real companion over TCP, a serial pty, or Bluetooth.
Repeatable testsmeshbench test runs a fixture on real firmware and checks its assertions, for your CI or MeshCore's.
Wireshark and SDREvery receiver's view of every frame over loopback UDP or as pcapng; IQ exported or streamed so an unmodified SDR client sees the band.
Batteries and solarWhether a node survives the winter where you want to put it.
DeterminismSame seed, same scenario, same answer — counter-based RNG, never a stateful stream shared across goroutines.
Boards

Measured, not claimed

Published board images, run under an emulator, and watched. Every row is a measurement — never a claim about the hardware. A blank means nobody has watched that board do that thing.

BoardMCUEmulatorHow far it got
Generic_E22_sx1262ESP32QEMUforwards, and answers after an idle
Heltec_t114nRF52840Renodeforwards, and answers after an idle
Heltec_t096nRF52840Renodeforwards, and answers after an idle
RAK_4631nRF52840Renodeforwards, and answers after an idle
Xiao_nrf52nRF52840Renodeforwards, and answers after an idle
Heltec_mesh_solarnRF52840Renodeforwards, and answers after an idle
Heltec_v3ESP32-S3QEMUforwards, and answers after an idle
LilyGo_TDeckESP32-S3QEMUforwards, and answers after an idle
Ebyte_EoRa-S3ESP32-S3QEMUforwards, and answers after an idle
Xiao_S3_WIOESP32-S3QEMUforwards; idle behaviour not measurable yet
Station_G2ESP32-S3no emulation wiring recorded yet
Heltec_v2ESP32carries an SX1276, which is not modelled

Forwarding is the row worth reading: it means the board took somebody else's packet off the air and put it back on, judged at the board itself, which is what separates a member of a mesh from a node that talks to itself. Measured one board at a time on an idle machine, on 4 September 2026 — several emulators at once make a twelve-core machine fall behind the wall clock, and a board running late looks exactly like a board that is broken. The two boards with no emulator have never been attempted rather than tried and failed. The full matrix has a column per capability.

Honesty about the model

The simulator is kinder than the air

No multipath, no oscillator error, no body loss, bare-earth terrain unless you load buildings, and an ESP32's Wi-Fi and Bluetooth stubbed rather than simulated.

Treat every result as a best case

Nearly every known bias points the same way, which is what makes the tool usable: if it says a link will not work, believe it; if it says a link will work marginally, go and measure.

And it is not buried

It is stated in the interface, on every result, and What it does not do is a long, specific and maintained account of what the model omits, what it gets measurably wrong, and in which direction — including the parts never checked against real air.