ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
web_terminal.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file web_terminal.h
6 * @brief Browser "web serial" terminal over WebSocket (PROTOCORE_ENABLE_WEB_TERMINAL).
7 *
8 * A zero-heap equivalent of the WebSerial-style remote serial monitor: it serves
9 * a self-contained terminal web page and a WebSocket endpoint on the same path.
10 * Device output is broadcast to every connected browser; each line a browser
11 * sends is delivered to a command callback. Rides the library's existing
12 * WebSocket layer (no extra connection state), so it is TLS-agnostic - the page
13 * auto-selects ws:// or wss:// from the page's own scheme.
14 *
15 * A line is built with the frame engine and handed over as text, so the shape is a
16 * `static const mmgr_field[]` in rodata rather than a format string parsed per call.
17 *
18 * @code
19 * static const mmgr_field SAID[] = {{MMGR_FK_LIT, 0, 10, "you said: "}, MMGR_STR,
20 * {MMGR_FK_LIT, 0, 1, "\n"}, MMGR_END};
21 * void on_cmd(const char *line, uint8_t client) {
22 * char out[64];
23 * EMBED_CALL(numer.build, NumerosCfg, .out = out, .cap = sizeof(out), .spec = SAID, .vals = (const
24 * mmgr_fval[]){MMGR_VSTR(line)}, .nvals = 1); protocore_web_terminal_print(out);
25 * }
26 * void setup() {
27 * // ... wifi + on_http(...) ...
28 * protocore_web_terminal_begin("/terminal");
29 * protocore_web_terminal_on_command(on_cmd);
30 * begin_http(80);
31 * }
32 * @endcode
33 *
34 * No-op stubs when PROTOCORE_ENABLE_WEB_TERMINAL is 0.
35 */
36
37#ifndef PROTOCORE_WEB_TERMINAL_H
38#define PROTOCORE_WEB_TERMINAL_H
39
40#include "protocore_config.h" // the entry point: protocore_types.h for the widths
41
42#if PROTOCORE_ENABLE_WEB_TERMINAL
43
45
46// PROTOCORE_WEB_TERMINAL_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums it
47// into its arena. A caller takes them once and passes the pointer to every call. How they are
48// carved is this module's and is never named here.
49
50/**
51 * @brief Callback for a line typed in a connected browser terminal.
52 * @param line Null-terminated command text (no trailing newline).
53 * @param client_id WebSocket client index that sent it (ws_pool[] slot).
54 */
55typedef void (*TermCommandCb)(const char *line, uint8_t client_id);
56
57typedef void (*TermCommandCb)(const char *line, uint8_t client_id);
58
59/** @brief What begin takes. */
60typedef struct
61{
62 const char *path;
63} WebTerminalBeginArgs;
64
65/** @brief What on_command takes. */
66typedef struct
67{
68 TermCommandCb cb;
69} WebTerminalOnCommandArgs;
70
71/** @brief What print takes. */
72typedef struct
73{
74 const char *s;
75} WebTerminalPrintArgs;
76
77/** @brief What println takes. */
78typedef struct
79{
80 const char *s;
81} WebTerminalPrintlnArgs;
82typedef struct
83{
84 WebTerminalBeginArgs begin_args;
85 WebTerminalOnCommandArgs on_command_args;
86 WebTerminalPrintArgs print_args;
87 WebTerminalPrintlnArgs println_args;
88 proto_bool ok;
89 uint16_t value;
90} WebTerminalVars;
91
92/** @brief The operands and the outcome. */
93extern WebTerminalVars WebTerminalV;
94
95/** @brief The entries. */
96typedef struct
97{
98 void (*const begin)(uint8_t *work);
99 void (*const on_command)(uint8_t *work);
100 void (*const print)(uint8_t *work);
101 void (*const println)(uint8_t *work);
102 void (*const client_count)(uint8_t *work);
103} WebTerminalNs;
104
105// What the table binds, defined once in the .c and taking one parameter each: everything
106// else an entry needs is an operand in WebTerminalV or a region of the borrow at a fixed offset.
107void protocore_web_terminal_begin(uint8_t *work);
108void protocore_web_terminal_on_command(uint8_t *work);
109void protocore_web_terminal_print(uint8_t *work);
110void protocore_web_terminal_println(uint8_t *work);
111void protocore_web_terminal_client_count(uint8_t *work);
112
113// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
114// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
115// `WebTerminal.begin(work)` resolves to a named function and becomes a DIRECT call. An extern table
116// leaves the call indirect and the symbol live at every level, -O2 -flto included.
117static const WebTerminalNs WebTerminal __attribute__((unused)) = {
118 .begin = protocore_web_terminal_begin,
119 .on_command = protocore_web_terminal_on_command,
120 .print = protocore_web_terminal_print,
121 .println = protocore_web_terminal_println,
122 .client_count = protocore_web_terminal_client_count,
123};
124
125/**
126 * @brief The PROTOCORE_WEB_TERMINAL_BORROW bytes this module's state lives in.
127 *
128 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
129 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
130 * walks, so the state lasts the life of the program.
131 *
132 * @return the span.
133 */
134uint8_t *protocore_web_terminal_span(void);
135
137
138#endif // PROTOCORE_ENABLE_WEB_TERMINAL
139
140#endif // PROTOCORE_WEB_TERMINAL_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97