---
title: "A touch panel for the gym gate, in Rust"
description: "Firmware for an ESP32-P4 touch panel that reads an RFID card at a climbing gym's gate and shows the verdict that the desk software sends back."
date: 2026-11-05T12:10:00+01:00
lastmod: 2026-11-05T13:51:01+01:00
url: https://klimek.link/projects/gate-panel-firmware/
author: "Marcin Klimek"
source: https://klimek.link/projects/gate-panel-firmware/
---

# A touch panel for the gym gate, in Rust

The gate of a climbing gym needs something climbers can tap a card on and see an answer. For [Backdoor](/projects/backdoor/) that's a small touch panel I wrote firmware for: an **ESP32-P4** dev board with a 7-inch 1024×600 screen and an RFID reader.

It does four things. It reads the card, sends the number to the desk software, waits for allowed, denied or error, and paints the answer in a colour with a line of text. After a timeout it goes back to a splash screen. The panel decides nothing itself, because the passes, the benefit cards and the rules all live on the desk computer.

## One cable

The panel talks to the host over the USB Serial/JTAG port, the same cable that carries the console and the flash. Messages are one JSON object per line. The sounds for the panel play on the desk computer, not on the board. Card numbers are masked in the logs, down to the last four characters.

## What the hardware did to me

The firmware is Rust on ESP-IDF, with LVGL for the screens. The display and touch controllers are set up in C. The touch controller reports 800×480 on a 1024×600 panel, so I scale the coordinates myself. The reader port has no level shifter, so a 5 V reader needs a series resistor or a divider.

Flashing took a while to get right. This chip revision needs `--no-stub`, and with `cargo run` or older espflash versions the board panics before `app_main` even starts, so the build scripts run the right esptool steps and nothing else.

Cards have been working at the gate since September 2026.

## Testing without a gate

Every screen has a simulator on the Mac that uses the same LVGL code as the device, with a window and a mouse in place of the display and touch. The reader's frame parser runs in host tests, including a reference frame commented byte by byte, and a test for the end byte, which nothing checked until a review pointed it out.

The text sanitizer has a canary test too, which catches a buffer overflow when one character is replaced by several.

Source: https://klimek.link/projects/gate-panel-firmware/
