Layer: L7 Application ยท Build flags: PC_ENABLE_GPIO_MAP
What this example teaches
This declares a compile-time table of GPIO pins (number, label, direction) and serves them at GET /gpio as JSON with live levels; POST /gpio (body pin=<n>&level=0|1) drives a pin marked as an output. A small inline page at / polls the JSON and renders the pin map with toggle buttons - a zero-dependency browser diagnostics tool. The JSON serializer and the control parser are host-tested; only the digital read/write run on the ESP32.
Declare the pins, then mount the endpoint. The table is caller-owned and must outlive the server; mark a pin PC_GPIO_OUT to make it drivable from the panel:
static pc_gpio_pin gpio_pins[] = {
{2, "Onboard LED", pc_gpio_dir::PC_GPIO_OUT, 0},
{0, "BOOT button", pc_gpio_dir::PC_GPIO_IN_PULLUP, 0},
{4, "Relay", pc_gpio_dir::PC_GPIO_OUT, 0},
{34, "ADC sense", pc_gpio_dir::PC_GPIO_IN, 0},
};
pc_gpio_map_begin(server, "/gpio", gpio_pins, gpio_count);
pc_gpio_map_begin() applies pinMode for each entry and registers both the JSON read route and the write route, so the only application code left is to serve the page that drives it.
Build and run
pio ci --board=esp32dev --project-option="framework=arduino" \
--project-option="build_flags=-DPC_ENABLE_GPIO_MAP=1" \
--lib="." examples/L7-Application/GpioMap/GpioMap.ino
Flash, then open http://<ip>/ for the live pin map, or hit the API directly:
curl http://<ip>/gpio # {"pins":[...]}
curl -X POST http://<ip>/gpio --data "pin=2&level=1" # drive an output high
Annotated source
The complete sketch (GpioMap.ino), reproduced verbatim with added explanatory comments. The inline DIAG_PAGE HTML/JS string is elided here for length (see the source); it just fetches /gpio, renders a table, and POSTs toggles.
#define PC_ENABLE_GPIO_MAP 1
static const char *SSID = "YOUR_SSID";
static const char *PASSWORD = "YOUR_PASSWORD";
static pc_gpio_pin gpio_pins[] = {
{2, "Onboard LED", pc_gpio_dir::PC_GPIO_OUT, 0},
{0, "BOOT button", pc_gpio_dir::PC_GPIO_IN_PULLUP, 0},
{4, "Relay", pc_gpio_dir::PC_GPIO_OUT, 0},
{34, "ADC sense", pc_gpio_dir::PC_GPIO_IN, 0},
};
static const uint8_t gpio_count = sizeof(gpio_pins) / sizeof(gpio_pins[0]);
static const char DIAG_PAGE[] = R"HTML(... inline HTML/JS elided; see the source ...)HTML";
void setup()
{
Serial.print("Connecting to WiFi");
{
delay(250);
Serial.print('.');
}
Serial.printf("IP: %u.%u.%u.%u\n", (unsigned)(ip & 0xFF), (unsigned)((ip >> 8) & 0xFF),
(unsigned)((ip >> 16) & 0xFF), (unsigned)((ip >> 24) & 0xFF));
pc_gpio_map_begin(server, "/gpio", gpio_pins, gpio_count);
}
void loop()
{
}
Single-port HTTP server with deterministic, zero-allocation execution.
void send(uint8_t slot_id, int code, const char *content_type, const char *payload)
Send an HTTP response with a body and close the connection.
int32_t begin(const WebServerConfig *cfg=nullptr)
Initialize all connection slots and open all registered listeners.
void on(const char *path, HttpMethod method, Handler callback)
Register a route handler.
void handle()
Drive the server - call every Arduino loop() iteration.
Browser GPIO pin-mapper / diagnostics (PC_ENABLE_GPIO_MAP).
bool init_wifi_physical(const char *, const char *)
Connect to a WiFi access point.
uint32_t pc_net_egress_ip(void)
IPv4 (network byte order) of the current egress interface, or 0 if none.
bool wifi_ready()
True if the WiFi station link is up (associated + an IP is assigned).
Layer 1 (Physical) - link bring-up and live egress-interface reporting.
Layer 7 (Application) - public HTTP routing API.
@ HTTP_GET
Safe, idempotent read.
Fully-parsed HTTP/1.1 request.