CHGame 0.3.0
Libraries for the CHGame handheld
Loading...
Searching...
No Matches
Debug.h
Go to the documentation of this file.
1/// @file Debug.h
2/// @brief The serial debug protocol (CHGAME_DEBUG builds only; see chgame/Config.h).
3///
4/// Line-based ASCII over the USB CDC port, or the simulator's pipe. The
5/// simulator, tools/chsim/chdrive.py and tools/device.py run scripts through
6/// it, on the PC and on the board alike.
7///
8/// In a release build every call here is an empty inline, so a sketch calls
9/// them without `#if`.
10#pragma once
11#include <stdint.h>
12#include "Config.h"
13
14/// @defgroup chgame_debug Debug protocol
15/// @ingroup lib_chgame
16/// @brief dbg::: the serial protocol the simulator and the PC tools drive a game through.
17///
18/// A game calls dbg::begin() at the top of `setup()` and dbg::poll() at the
19/// top of `loop()`; the rest is optional. With CHGAME_DEBUG off (a release
20/// build) every call is an empty inline that costs nothing.
21///
22/// | Command | Answer / effect |
23/// |---|---|
24/// | `?` | the game's hello line, e.g. `CHCR 0.1` |
25/// | `S` | `FB <frame> 8224` and a newline, then 8192 framebuffer + 32 palette bytes |
26/// | `K <hex>` | hold these buttons (ORed with the real ones); `K` alone releases |
27/// | `L1` / `L0` | lockstep on / off (on: the game only advances on `N`) |
28/// | `N <k>` | run k frames, then answer `OK <frame>` |
29/// | `P` | `PERF rnd=<us> max=<us> late=<n> frames=<n> stk=<b>` (+ `fstk=<b>` with a second frame stack, + host ns in the sim) |
30/// | `T` | `PROF <slot>=<us> ...` section timings (CHGAME_PROFILE) |
31/// | `B` | reboot into the CHGame bootloader |
32/// | `!` | `FAULT none`, or the crash before the last restart (the core's fault handler: A restarts after one) as `FAULT mcause=<hex> mepc=<hex> mtval=<hex> ra=<hex> sp=<hex>` |
33/// | `Q` | (simulator) `CAL <ns> x5`: host time of CHGfx's benchmark primitives, for estimated device times (chdrive's cal) |
34/// | anything else | goes to the game's hook: `OK` if it took it, else `ERR` |
35/// @{
36
37/// @brief The serial debug protocol.
38namespace dbg {
39
40#if CHGAME_DEBUG
41/// @brief Start the protocol: at the top of `setup()`.
42/// @param hello The line `?` answers: the game's id and version (e.g.
43/// "CHCR 0.1"), so a tool can check it is talking to the right
44/// game. Each game needs its own id.
45/// @details Also paints the stack for its high-water mark (P's stk=) and
46/// picks up the record of a crash before the last restart (`!`).
47void begin(const char *hello);
48/// @brief Read and answer commands: at the top of `loop()`, before nextFrame().
49void poll(); // at the top of loop(): serial input
50/// @brief Frame timing for `P`: call when the logic tick starts.
52/// @brief Frame timing for `P`: call when drawing starts.
54/// @brief Frame timing for `P`: call when drawing ends (before the flush).
56/// @brief Send text to the host as it is (no newline added).
57/// @param s The text.
58void print(const char *s);
59/// @brief In the simulator, block until input may have arrived (elsewhere nothing).
60void waitInput(); // the simulator: block until input may have arrived
61/// @brief Parse a number from a command's arguments, for a game's hook.
62/// @param p The text; skips leading spaces and commas, and is left after the number.
63/// @param base 10 or 16.
64/// @return The number (0 if there are no digits).
65uint32_t parseNum(const char *&p, uint8_t base); // skips leading spaces/commas
66/// @brief The game's own commands, or nullptr.
67/// @details Called with the command's first character and the rest of the
68/// line; returns true if it handled the command (the host gets "OK"), false
69/// if not ("ERR").
70extern bool (*hook)(char cmd, const char *args);
71/// @brief The longest command line, in characters.
72static const uint8_t LINE = 100; // the longest command line
73/// @brief Hold the game's commands while it is busy, in a caller's buffer.
74/// @details A game busy with something long (a search) can hold its commands:
75/// while busy(cmd) is true a command waits (answered HELD at once, OK/ERR
76/// once it has run) while N, S, P and the rest go on working.
77/// @param busy Returns true while a command must wait.
78/// @param buf LINE bytes for the waiting command.
79void holdInto(bool (*busy)(char cmd), char *buf);
80/// @brief holdInto() with a buffer of its own (which exists only in a game that calls this).
81/// @param busy Returns true while a command must wait.
82inline void holdWhile(bool (*busy)(char cmd)) { static char held[LINE]; holdInto(busy, held); }
83/// @brief Report a second stack's high-water mark in `P` (fstk=): frames drawn
84/// from inside a search, for instance.
85/// @param lo,hi The stack's bounds (it is painted now).
86void frameStack(uint32_t *lo, uint32_t *hi);
87#if CHGAME_PROFILE
88/// @brief Start a profiled frame (CHGAME_PROFILE builds): `T` reports averages per call.
89/// @details prof(i) charges the time since the previous prof() to slot i
90/// (0-11); T reports and resets the averages per profStart().
91void profStart();
92/// @brief Charge the time since the previous prof() to a slot.
93/// @param slot 0-11.
94void prof(uint8_t slot);
95#else
96inline void profStart() {}
97inline void prof(uint8_t) {}
98#endif
99#else
100inline void begin(const char *) {}
101inline void poll() {}
102inline void markUpdateStart() {}
103inline void markRenderStart() {}
104inline void markRenderEnd() {}
105inline void print(const char *) {}
106inline void waitInput() {}
107inline void holdWhile(bool (*)(char)) {}
108inline void frameStack(uint32_t *, uint32_t *) {}
109inline void profStart() {}
110inline void prof(uint8_t) {}
111#endif
112
113} // namespace dbg
114
115/// @}
The CHGame library's build switches.
The serial debug protocol.
Definition Debug.h:38
static const uint8_t LINE
The longest command line, in characters.
Definition Debug.h:72
void markRenderEnd()
Frame timing for P: call when drawing ends (before the flush).
uint32_t parseNum(const char *&p, uint8_t base)
Parse a number from a command's arguments, for a game's hook.
void holdWhile(bool(*busy)(char cmd))
holdInto() with a buffer of its own (which exists only in a game that calls this).
Definition Debug.h:82
void poll()
Read and answer commands: at the top of loop(), before nextFrame().
void print(const char *s)
Send text to the host as it is (no newline added).
void profStart()
Start a profiled frame (CHGAME_PROFILE builds): T reports averages per call.
void waitInput()
In the simulator, block until input may have arrived (elsewhere nothing).
void markUpdateStart()
Frame timing for P: call when the logic tick starts.
void markRenderStart()
Frame timing for P: call when drawing starts.
void frameStack(uint32_t *lo, uint32_t *hi)
Report a second stack's high-water mark in P (fstk=): frames drawn from inside a search,...
void begin(const char *hello)
Start the protocol: at the top of setup().
void holdInto(bool(*busy)(char cmd), char *buf)
Hold the game's commands while it is busy, in a caller's buffer.
void prof(uint8_t slot)
Charge the time since the previous prof() to a slot.
bool(* hook)(char cmd, const char *args)
The game's own commands, or nullptr.