OXYGENHUB
# 7c83b415d7cc retro-remote-debug-controller / core / retro_control.h
5.3 KiB · Objective-C · last changed core: guard the public header with extern "C" for C++ consumers 3 months ago source blame history raw
961b3c61 Andy McCall 1
/* retro_control.h — portable emulator control server (see ../SPEC.md).
2
 *
3
 * A retro-platform emulator implements the small read-only backend below and
4
 * calls retro_control_start(). The shared server (retro_control.c) owns the
5
 * socket loop, HTTP parsing, PPM/JSON encoding, and control flow
6
 * (pause / step / free-run). It always binds 127.0.0.1. Contract 0.1.0.
7
 *
8
 * Integration is three calls in the emulator's main loop:
9
 *   retro_control_service();                 // once per iteration (cheap)
10
 *   if (!retro_control_running()) { idle; }  // gate advancing the machine
11
 *   ... run one instruction / frame ...
12
 *   if (frame_completed) retro_control_on_frame();
13
 *
14
 * Threading: the server runs on its own thread but never touches machine state
15
 * there. State-reading endpoints (/mem, /regs, /screenshot) are executed inside
16
 * retro_control_service() ON THE EMULATOR THREAD, so every read is consistent.
17
 * The backend callbacks are therefore called from the emulator thread (except
18
 * get_frame_count, which the server may also read for /status — make it a plain
19
 * atomic-ish counter read).
20
 */
21
#ifndef RETRO_CONTROL_H
22
#define RETRO_CONTROL_H
23
24
#include <stdint.h>
25
#include <stddef.h>
26
7c83b415 Andy McCall ↶ 27
#ifdef __cplusplus
28
extern "C" {
29
#endif
30
674b8447 Andy McCall ↶ 31
/* Highest contract the core implements. The server advertises the highest level
32
 * whose backend callbacks are all present: 0.3.0 needs inject_key + write_mem +
33
 * capture_audio; 0.2.0 needs inject_key; else 0.1.0. Keeps a partial backend
34
 * honest. */
35
#define RETRO_CONTROL_CONTRACT "0.3.0"
961b3c61 Andy McCall 36
37
/* Native framebuffer pixel layout; the server swizzles to PPM RGB. */
38
typedef enum {
39
    RETRO_PIX_RGB888 = 0,   /* 3 bytes/px: R,G,B                       */
40
    RETRO_PIX_RGBA8888,     /* 4 bytes/px: R,G,B,A                     */
41
    RETRO_PIX_BGRA8888      /* 4 bytes/px: B,G,R,A (x16 framebuffer)   */
42
} retro_pix_fmt_t;
43
44
typedef struct {
45
    const uint8_t *pixels;  /* start of the current complete frame     */
46
    int width;
47
    int height;
48
    retro_pix_fmt_t fmt;
49
} retro_framebuffer_t;
50
689a9ccb Andy McCall ↶ 51
/* Key action for inject_key (0.2). */
52
typedef enum {
53
    RETRO_KEY_TAP  = 0,   /* press then release */
54
    RETRO_KEY_DOWN = 1,   /* press / hold       */
55
    RETRO_KEY_UP   = 2    /* release            */
56
} retro_key_action_t;
57
961b3c61 Andy McCall 58
/* The emulator implements these. Any may be NULL: the matching endpoint then
59
 * returns 501 Not Implemented. */
60
typedef struct retro_control_backend {
61
    const char *platform;   /* "x16" | "neo6502" | "agon" | ...        */
62
    const char *emulator;   /* human name, e.g. "x16emu"               */
63
64
    /* Debug-read up to min(len, out_cap) bytes at addr into out, side-effect
65
     * free. bank is the optional bank selector (<0 = current bank). Returns the
66
     * number of bytes written. */
67
    uint32_t (*read_mem)(uint32_t addr, int32_t bank, uint32_t len,
68
                         uint8_t *out, uint32_t out_cap);
69
70
    /* Write a JSON object of registers into buf (NUL-terminated). */
71
    void (*get_regs_json)(char *buf, size_t cap);
72
73
    /* Report the current complete-frame framebuffer. */
74
    void (*get_framebuffer)(retro_framebuffer_t *out);
75
76
    /* Monotonic completed-frame counter. */
77
    uint64_t (*get_frame_count)(void);
689a9ccb Andy McCall ↶ 78
79
    /* 0.2: inject a key. is_text=1 => `value` is a character code point;
80
     * is_text=0 => `value` is a raw platform key code. `action` is a
81
     * retro_key_action_t. Return 1 on success, 0 if unmappable (server -> 400).
82
     * NULL => /key returns 501 and the server advertises contract 0.1.0. */
83
    int (*inject_key)(int is_text, uint32_t value, int action);
84
85
    /* 0.2: soft/cold reset the machine. NULL => /reset returns 501. */
86
    void (*reset)(void);
674b8447 Andy McCall ↶ 87
88
    /* 0.3: write len bytes from `in` at addr (debug/state poke; bank<0 =
89
     * current). Intended for RAM/state — I/O-register writes may trigger device
90
     * side effects. Return bytes written. NULL => POST /mem returns 501. */
91
    uint32_t (*write_mem)(uint32_t addr, int32_t bank, uint32_t len,
92
                          const uint8_t *in);
93
94
    /* 0.3: drain up to `cap` interleaved signed-16-bit audio samples the
95
     * emulator has synthesised since the last call into `out`; set *rate and
96
     * *channels; set *dropped to samples lost to overflow since the last drain.
97
     * Return the number of int16 samples written. NULL => /audio returns 501. */
98
    uint32_t (*capture_audio)(int16_t *out, uint32_t cap,
99
                              int *rate, int *channels, uint32_t *dropped);
961b3c61 Andy McCall 100
} retro_control_backend_t;
101
102
/* Start the server thread bound to 127.0.0.1:port. Non-blocking; 0 on success,
103
 * negative on error. backend must outlive the server. */
104
int  retro_control_start(int port, const retro_control_backend_t *backend);
105
106
/* Drain a pending control request. Call once per main-loop iteration, at an
107
 * instruction/frame boundary. Cheap no-op when idle and when control is off. */
108
void retro_control_service(void);
109
110
/* Nonzero => the machine should advance this iteration. Returns 1 always when
111
 * control is off or the machine is free-running; 0 when paused with no steps
112
 * left. */
113
int  retro_control_running(void);
114
115
/* Call when a video frame completes. Drives /step (decrements the step budget,
116
 * halts and answers when it reaches zero). No-op when control is off. */
117
void retro_control_on_frame(void);
118
119
/* Stop the server (optional; process exit is fine too). */
120
void retro_control_stop(void);
7c83b415 Andy McCall ↶ 121
122
#ifdef __cplusplus
123
}
124
#endif
961b3c61 Andy McCall 125
126
#endif /* RETRO_CONTROL_H */