From 07c7a6adb7ccd6b037f48a6e9e5e9afbce1a24d3 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Tue, 26 May 2026 19:31:56 +0800 Subject: [PATCH 1/5] Add live cheat command control --- cheat_cmd.cpp | 78 +++++++++++++++++++++++++++++++++ cheat_cmd.h | 6 +++ cheats.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ cheats.h | 13 ++++++ input.cpp | 2 + 5 files changed, 218 insertions(+) create mode 100644 cheat_cmd.cpp create mode 100644 cheat_cmd.h diff --git a/cheat_cmd.cpp b/cheat_cmd.cpp new file mode 100644 index 000000000..cd2286ae8 --- /dev/null +++ b/cheat_cmd.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +#include "cheats.h" +#include "cheat_cmd.h" + +static const char *skip_space(const char *s) +{ + while (*s && isspace((unsigned char)*s)) s++; + return s; +} + +static bool parse_token(const char **cmd, char *token, size_t token_size) +{ + const char *s = skip_space(*cmd); + size_t len = 0; + + while (s[len] && !isspace((unsigned char)s[len])) len++; + if (!len || len >= token_size) return false; + + memcpy(token, s, len); + token[len] = 0; + *cmd = s + len; + return true; +} + +static const char *cheat_cmd_status(int status) +{ + switch (status) + { + case CHEATS_CMD_OK: return "ok"; + case CHEATS_CMD_NO_CHEATS: return "no cheats loaded"; + case CHEATS_CMD_NOT_FOUND: return "not found"; + case CHEATS_CMD_LOAD_FAILED: return "load failed"; + case CHEATS_CMD_NO_ROOM: return "no room"; + default: return "error"; + } +} + +void cheat_cmd(const char *cmd) +{ + char action[16]; + + if (!parse_token(&cmd, action, sizeof(action))) + { + printf("MiSTer_cmd cheat: missing command\n"); + return; + } + + if (!strcmp(action, "clear")) + { + int status = cheats_clear_enabled(); + printf("MiSTer_cmd cheat clear: %s\n", cheat_cmd_status(status)); + return; + } + + const char *name = skip_space(cmd); + if (!*name) + { + printf("MiSTer_cmd cheat %s: missing name\n", action); + return; + } + + int status; + if (!strcmp(action, "on")) status = cheats_set_enabled_by_name(name, true); + else if (!strcmp(action, "off")) status = cheats_set_enabled_by_name(name, false); + else if (!strcmp(action, "toggle")) status = cheats_toggle_by_name(name); + else + { + printf("MiSTer_cmd cheat: unknown command '%s'\n", action); + return; + } + + printf("MiSTer_cmd cheat %s '%s': %s\n", action, name, cheat_cmd_status(status)); +} diff --git a/cheat_cmd.h b/cheat_cmd.h new file mode 100644 index 000000000..470d0e94e --- /dev/null +++ b/cheat_cmd.h @@ -0,0 +1,6 @@ +#ifndef CHEAT_CMD_H +#define CHEAT_CMD_H + +void cheat_cmd(const char *cmd); + +#endif diff --git a/cheats.cpp b/cheats.cpp index 26ed2d18d..cc43bb64f 100644 --- a/cheats.cpp +++ b/cheats.cpp @@ -348,6 +348,7 @@ void cheats_print() static void cheats_send() { static uint8_t buff[CHEAT_SIZE]; + memset(buff, 0, sizeof(buff)); int pos = 0; for (int i = 0; i < cheats_available(); i++) @@ -459,6 +460,124 @@ void cheats_toggle() } } +static int cheats_find_by_name(const char *name) +{ + if (!name || !*name) return -1; + + for (int i = 0; i < cheats_available(); i++) + { + if (!strcmp(cheats[i].name, name)) return i; + } + + return -1; +} + +static int cheats_external_load_entry(int idx) +{ + if (idx < 0 || idx >= cheats_available()) return CHEATS_CMD_NOT_FOUND; + if (cheats[idx].cheatData) return CHEATS_CMD_OK; + if (!cheat_zip[0]) return CHEATS_CMD_LOAD_FAILED; + + static char filename[1024]; + fileTYPE f = {}; + snprintf(filename, sizeof(filename), "%s/%s", cheat_zip, cheats[idx].name); + if (!FileOpen(&f, filename)) + { + printf("Cannot open cheat file %s.\n", filename); + return CHEATS_CMD_LOAD_FAILED; + } + + int res = CHEATS_CMD_LOAD_FAILED; + int len = f.size; + if (!len || (len % cheat_unit_size)) + { + printf("Cheat file %s has incorrect length %d -> skipping.\n", filename, len); + } + else if (((len / cheat_unit_size) + cheats_loaded()) <= cheat_max_active) + { + cheats[idx].cheatData = new char[len]; + if (cheats[idx].cheatData) + { + if (FileReadAdv(&f, cheats[idx].cheatData, len) == len) + { + cheats[idx].cheatSize = len; + res = CHEATS_CMD_OK; + } + else + { + printf("Cannot read cheat file %s.\n", filename); + delete[] cheats[idx].cheatData; + cheats[idx].cheatData = NULL; + cheats[idx].cheatSize = 0; + } + } + else + { + printf("Could not allocate required memory (%d) for cheat file %s.\n", len, filename); + } + } + else + { + printf("No more room in current selection for cheat file %s.\n", filename); + res = CHEATS_CMD_NO_ROOM; + } + + FileClose(&f); + return res; +} + +static int cheats_external_set_enabled(int idx, bool enabled) +{ + if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; + if (idx < 0 || idx >= cheats_available()) return CHEATS_CMD_NOT_FOUND; + if (cheats[idx].enabled == enabled) return CHEATS_CMD_OK; + + if (enabled) + { + int res = cheats_external_load_entry(idx); + if (res != CHEATS_CMD_OK) return res; + if (((cheats[idx].cheatSize / cheat_unit_size) + cheats_loaded()) > cheat_max_active) return CHEATS_CMD_NO_ROOM; + } + + cheats[idx].enabled = enabled; + cheats_send(); + return CHEATS_CMD_OK; +} + +int cheats_set_enabled_by_name(const char *name, bool enabled) +{ + if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; + return cheats_external_set_enabled(cheats_find_by_name(name), enabled); +} + +int cheats_toggle_by_name(const char *name) +{ + if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; + + int idx = cheats_find_by_name(name); + if (idx < 0) return CHEATS_CMD_NOT_FOUND; + + return cheats_external_set_enabled(idx, !cheats[idx].enabled); +} + +int cheats_clear_enabled() +{ + if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; + + bool changedCheats = false; + for (int i = 0; i < cheats_available(); i++) + { + if (cheats[i].enabled) + { + cheats[i].enabled = false; + changedCheats = true; + } + } + + if (changedCheats) cheats_send(); + return CHEATS_CMD_OK; +} + int cheats_loaded() { return loaded; diff --git a/cheats.h b/cheats.h index 040457731..8c8ed2f8b 100644 --- a/cheats.h +++ b/cheats.h @@ -9,6 +9,19 @@ void cheats_print(); void cheats_toggle(); int cheats_loaded(); +enum +{ + CHEATS_CMD_OK = 0, + CHEATS_CMD_NO_CHEATS = -1, + CHEATS_CMD_NOT_FOUND = -2, + CHEATS_CMD_LOAD_FAILED = -3, + CHEATS_CMD_NO_ROOM = -4 +}; + +int cheats_set_enabled_by_name(const char *name, bool enabled); +int cheats_toggle_by_name(const char *name); +int cheats_clear_enabled(); + void cheats_init_arcade(int unit_size, int max_active); void cheats_add_arcade(const char *name, const char *cheatData, int cheatSize); void cheats_finalize_arcade(); diff --git a/input.cpp b/input.cpp index 18a43cbb1..bbb98dc03 100644 --- a/input.cpp +++ b/input.cpp @@ -36,6 +36,7 @@ #include "frame_timer.h" #include "scaler.h" #include "file_io.h" +#include "cheat_cmd.h" #include "support/zaparoo/alt_launcher.h" #define NUMDEV 30 @@ -6238,6 +6239,7 @@ int input_test(int getchar) printf("MiSTer_cmd: %s\n", cmd); if (!strncmp(cmd, "fb_cmd", 6)) video_cmd(cmd); else if (!strncmp(cmd, "video_mode ", 11)) video_mode_cmd(cmd + 11); + else if (!strncmp(cmd, "cheat ", 6)) cheat_cmd(cmd + 6); else if (!strncmp(cmd, "load_core ", 10)) { if(isXmlName(cmd)) xml_load(cmd + 10); From a67d0d87c7e845b208d69e79728880bf606e89c6 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Wed, 27 May 2026 16:30:16 +0800 Subject: [PATCH 2/5] Move cheat command code under Zaparoo support --- cheat_cmd.h | 6 -- cheats.cpp | 86 +++---------------- input.cpp | 4 +- .../zaparoo/cheat_cmd.cpp | 11 +-- support/zaparoo/cheat_cmd.h | 3 + 5 files changed, 23 insertions(+), 87 deletions(-) delete mode 100644 cheat_cmd.h rename cheat_cmd.cpp => support/zaparoo/cheat_cmd.cpp (97%) create mode 100644 support/zaparoo/cheat_cmd.h diff --git a/cheat_cmd.h b/cheat_cmd.h deleted file mode 100644 index 470d0e94e..000000000 --- a/cheat_cmd.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CHEAT_CMD_H -#define CHEAT_CMD_H - -void cheat_cmd(const char *cmd); - -#endif diff --git a/cheats.cpp b/cheats.cpp index cc43bb64f..52008cb77 100644 --- a/cheats.cpp +++ b/cheats.cpp @@ -348,7 +348,6 @@ void cheats_print() static void cheats_send() { static uint8_t buff[CHEAT_SIZE]; - memset(buff, 0, sizeof(buff)); int pos = 0; for (int i = 0; i < cheats_available(); i++) @@ -472,92 +471,31 @@ static int cheats_find_by_name(const char *name) return -1; } -static int cheats_external_load_entry(int idx) -{ - if (idx < 0 || idx >= cheats_available()) return CHEATS_CMD_NOT_FOUND; - if (cheats[idx].cheatData) return CHEATS_CMD_OK; - if (!cheat_zip[0]) return CHEATS_CMD_LOAD_FAILED; - - static char filename[1024]; - fileTYPE f = {}; - snprintf(filename, sizeof(filename), "%s/%s", cheat_zip, cheats[idx].name); - if (!FileOpen(&f, filename)) - { - printf("Cannot open cheat file %s.\n", filename); - return CHEATS_CMD_LOAD_FAILED; - } - - int res = CHEATS_CMD_LOAD_FAILED; - int len = f.size; - if (!len || (len % cheat_unit_size)) - { - printf("Cheat file %s has incorrect length %d -> skipping.\n", filename, len); - } - else if (((len / cheat_unit_size) + cheats_loaded()) <= cheat_max_active) - { - cheats[idx].cheatData = new char[len]; - if (cheats[idx].cheatData) - { - if (FileReadAdv(&f, cheats[idx].cheatData, len) == len) - { - cheats[idx].cheatSize = len; - res = CHEATS_CMD_OK; - } - else - { - printf("Cannot read cheat file %s.\n", filename); - delete[] cheats[idx].cheatData; - cheats[idx].cheatData = NULL; - cheats[idx].cheatSize = 0; - } - } - else - { - printf("Could not allocate required memory (%d) for cheat file %s.\n", len, filename); - } - } - else - { - printf("No more room in current selection for cheat file %s.\n", filename); - res = CHEATS_CMD_NO_ROOM; - } - - FileClose(&f); - return res; -} - -static int cheats_external_set_enabled(int idx, bool enabled) +int cheats_toggle_by_name(const char *name) { if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; - if (idx < 0 || idx >= cheats_available()) return CHEATS_CMD_NOT_FOUND; - if (cheats[idx].enabled == enabled) return CHEATS_CMD_OK; - if (enabled) - { - int res = cheats_external_load_entry(idx); - if (res != CHEATS_CMD_OK) return res; - if (((cheats[idx].cheatSize / cheat_unit_size) + cheats_loaded()) > cheat_max_active) return CHEATS_CMD_NO_ROOM; - } + int idx = cheats_find_by_name(name); + if (idx < 0) return CHEATS_CMD_NOT_FOUND; - cheats[idx].enabled = enabled; - cheats_send(); - return CHEATS_CMD_OK; -} + bool was_enabled = cheats[idx].enabled; + int old_entry = iSelectedEntry; + iSelectedEntry = idx; + cheats_toggle(); + iSelectedEntry = old_entry; -int cheats_set_enabled_by_name(const char *name, bool enabled) -{ - if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; - return cheats_external_set_enabled(cheats_find_by_name(name), enabled); + return (cheats[idx].enabled != was_enabled) ? CHEATS_CMD_OK : CHEATS_CMD_LOAD_FAILED; } -int cheats_toggle_by_name(const char *name) +int cheats_set_enabled_by_name(const char *name, bool enabled) { if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; int idx = cheats_find_by_name(name); if (idx < 0) return CHEATS_CMD_NOT_FOUND; + if (cheats[idx].enabled == enabled) return CHEATS_CMD_OK; - return cheats_external_set_enabled(idx, !cheats[idx].enabled); + return cheats_toggle_by_name(name); } int cheats_clear_enabled() diff --git a/input.cpp b/input.cpp index bbb98dc03..1f380e391 100644 --- a/input.cpp +++ b/input.cpp @@ -36,7 +36,7 @@ #include "frame_timer.h" #include "scaler.h" #include "file_io.h" -#include "cheat_cmd.h" +#include "support/zaparoo/cheat_cmd.h" #include "support/zaparoo/alt_launcher.h" #define NUMDEV 30 @@ -6239,7 +6239,7 @@ int input_test(int getchar) printf("MiSTer_cmd: %s\n", cmd); if (!strncmp(cmd, "fb_cmd", 6)) video_cmd(cmd); else if (!strncmp(cmd, "video_mode ", 11)) video_mode_cmd(cmd + 11); - else if (!strncmp(cmd, "cheat ", 6)) cheat_cmd(cmd + 6); + else if (!strncmp(cmd, "cheat ", 6)) zaparoo_cheat_cmd(cmd + 6); else if (!strncmp(cmd, "load_core ", 10)) { if(isXmlName(cmd)) xml_load(cmd + 10); diff --git a/cheat_cmd.cpp b/support/zaparoo/cheat_cmd.cpp similarity index 97% rename from cheat_cmd.cpp rename to support/zaparoo/cheat_cmd.cpp index cd2286ae8..bb0c3439b 100644 --- a/cheat_cmd.cpp +++ b/support/zaparoo/cheat_cmd.cpp @@ -1,11 +1,12 @@ -#include -#include +#include "cheat_cmd.h" + #include -#include #include +#include +#include +#include #include "cheats.h" -#include "cheat_cmd.h" static const char *skip_space(const char *s) { @@ -40,7 +41,7 @@ static const char *cheat_cmd_status(int status) } } -void cheat_cmd(const char *cmd) +void zaparoo_cheat_cmd(const char *cmd) { char action[16]; diff --git a/support/zaparoo/cheat_cmd.h b/support/zaparoo/cheat_cmd.h new file mode 100644 index 000000000..6979614d3 --- /dev/null +++ b/support/zaparoo/cheat_cmd.h @@ -0,0 +1,3 @@ +#pragma once + +void zaparoo_cheat_cmd(const char *cmd); From 9bd5b5451e43fe1d2aadb80a91fdfa4f47603ff9 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Wed, 27 May 2026 16:53:10 +0800 Subject: [PATCH 3/5] Limit cheat command hooks to accessors --- cheats.cpp | 55 +++++------------------- cheats.h | 16 ++----- support/zaparoo/cheat_cmd.cpp | 79 +++++++++++++++++++++++++++++++---- 3 files changed, 84 insertions(+), 66 deletions(-) diff --git a/cheats.cpp b/cheats.cpp index 52008cb77..49df7b071 100644 --- a/cheats.cpp +++ b/cheats.cpp @@ -459,61 +459,26 @@ void cheats_toggle() } } -static int cheats_find_by_name(const char *name) +const char *cheats_get_name(int idx) { - if (!name || !*name) return -1; - - for (int i = 0; i < cheats_available(); i++) - { - if (!strcmp(cheats[i].name, name)) return i; - } - - return -1; + if (idx < 0 || idx >= cheats_available()) return NULL; + return cheats[idx].name; } -int cheats_toggle_by_name(const char *name) +bool cheats_get_enabled(int idx) { - if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; - - int idx = cheats_find_by_name(name); - if (idx < 0) return CHEATS_CMD_NOT_FOUND; - - bool was_enabled = cheats[idx].enabled; - int old_entry = iSelectedEntry; - iSelectedEntry = idx; - cheats_toggle(); - iSelectedEntry = old_entry; - - return (cheats[idx].enabled != was_enabled) ? CHEATS_CMD_OK : CHEATS_CMD_LOAD_FAILED; + if (idx < 0 || idx >= cheats_available()) return false; + return cheats[idx].enabled; } -int cheats_set_enabled_by_name(const char *name, bool enabled) +int cheats_get_selected() { - if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; - - int idx = cheats_find_by_name(name); - if (idx < 0) return CHEATS_CMD_NOT_FOUND; - if (cheats[idx].enabled == enabled) return CHEATS_CMD_OK; - - return cheats_toggle_by_name(name); + return iSelectedEntry; } -int cheats_clear_enabled() +void cheats_set_selected(int idx) { - if (!cheats_available()) return CHEATS_CMD_NO_CHEATS; - - bool changedCheats = false; - for (int i = 0; i < cheats_available(); i++) - { - if (cheats[i].enabled) - { - cheats[i].enabled = false; - changedCheats = true; - } - } - - if (changedCheats) cheats_send(); - return CHEATS_CMD_OK; + if (idx >= 0 && idx < cheats_available()) iSelectedEntry = idx; } int cheats_loaded() diff --git a/cheats.h b/cheats.h index 8c8ed2f8b..98e026f79 100644 --- a/cheats.h +++ b/cheats.h @@ -9,18 +9,10 @@ void cheats_print(); void cheats_toggle(); int cheats_loaded(); -enum -{ - CHEATS_CMD_OK = 0, - CHEATS_CMD_NO_CHEATS = -1, - CHEATS_CMD_NOT_FOUND = -2, - CHEATS_CMD_LOAD_FAILED = -3, - CHEATS_CMD_NO_ROOM = -4 -}; - -int cheats_set_enabled_by_name(const char *name, bool enabled); -int cheats_toggle_by_name(const char *name); -int cheats_clear_enabled(); +const char *cheats_get_name(int idx); +bool cheats_get_enabled(int idx); +int cheats_get_selected(); +void cheats_set_selected(int idx); void cheats_init_arcade(int unit_size, int max_active); void cheats_add_arcade(const char *name, const char *cheatData, int cheatSize); diff --git a/support/zaparoo/cheat_cmd.cpp b/support/zaparoo/cheat_cmd.cpp index bb0c3439b..39f2f9e78 100644 --- a/support/zaparoo/cheat_cmd.cpp +++ b/support/zaparoo/cheat_cmd.cpp @@ -8,6 +8,14 @@ #include "cheats.h" +enum +{ + CHEAT_CMD_OK = 0, + CHEAT_CMD_NO_CHEATS = -1, + CHEAT_CMD_NOT_FOUND = -2, + CHEAT_CMD_LOAD_FAILED = -3 +}; + static const char *skip_space(const char *s) { while (*s && isspace((unsigned char)*s)) s++; @@ -32,15 +40,67 @@ static const char *cheat_cmd_status(int status) { switch (status) { - case CHEATS_CMD_OK: return "ok"; - case CHEATS_CMD_NO_CHEATS: return "no cheats loaded"; - case CHEATS_CMD_NOT_FOUND: return "not found"; - case CHEATS_CMD_LOAD_FAILED: return "load failed"; - case CHEATS_CMD_NO_ROOM: return "no room"; + case CHEAT_CMD_OK: return "ok"; + case CHEAT_CMD_NO_CHEATS: return "no cheats loaded"; + case CHEAT_CMD_NOT_FOUND: return "not found"; + case CHEAT_CMD_LOAD_FAILED: return "load failed"; default: return "error"; } } +static int find_cheat_by_name(const char *name) +{ + if (!name || !*name) return -1; + + for (int i = 0; i < cheats_available(); i++) + { + const char *cheat_name = cheats_get_name(i); + if (cheat_name && !strcmp(cheat_name, name)) return i; + } + + return -1; +} + +static int toggle_index(int idx) +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + if (idx < 0 || idx >= cheats_available()) return CHEAT_CMD_NOT_FOUND; + + bool was_enabled = cheats_get_enabled(idx); + int old_entry = cheats_get_selected(); + cheats_set_selected(idx); + cheats_toggle(); + cheats_set_selected(old_entry); + + return (cheats_get_enabled(idx) != was_enabled) ? CHEAT_CMD_OK : CHEAT_CMD_LOAD_FAILED; +} + +static int set_index_enabled(int idx, bool enabled) +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + if (idx < 0 || idx >= cheats_available()) return CHEAT_CMD_NOT_FOUND; + if (cheats_get_enabled(idx) == enabled) return CHEAT_CMD_OK; + + return toggle_index(idx); +} + +static int clear_enabled() +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + + int status = CHEAT_CMD_OK; + for (int i = 0; i < cheats_available(); i++) + { + if (cheats_get_enabled(i)) + { + int res = toggle_index(i); + if (res != CHEAT_CMD_OK) status = res; + } + } + + return status; +} + void zaparoo_cheat_cmd(const char *cmd) { char action[16]; @@ -53,7 +113,7 @@ void zaparoo_cheat_cmd(const char *cmd) if (!strcmp(action, "clear")) { - int status = cheats_clear_enabled(); + int status = clear_enabled(); printf("MiSTer_cmd cheat clear: %s\n", cheat_cmd_status(status)); return; } @@ -65,10 +125,11 @@ void zaparoo_cheat_cmd(const char *cmd) return; } + int idx = find_cheat_by_name(name); int status; - if (!strcmp(action, "on")) status = cheats_set_enabled_by_name(name, true); - else if (!strcmp(action, "off")) status = cheats_set_enabled_by_name(name, false); - else if (!strcmp(action, "toggle")) status = cheats_toggle_by_name(name); + if (!strcmp(action, "on")) status = set_index_enabled(idx, true); + else if (!strcmp(action, "off")) status = set_index_enabled(idx, false); + else if (!strcmp(action, "toggle")) status = toggle_index(idx); else { printf("MiSTer_cmd cheat: unknown command '%s'\n", action); From 48f5c50d5655ebe2da65f0be29d6e1fc2d099422 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Thu, 28 May 2026 08:14:53 +0800 Subject: [PATCH 4/5] Make cheats header self-contained --- cheats.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cheats.h b/cheats.h index 98e026f79..32f6b892f 100644 --- a/cheats.h +++ b/cheats.h @@ -1,6 +1,9 @@ #ifndef CHEATS_H #define CHEATS_H +#include +#include + void cheats_init(const char *rom_path, uint32_t romcrc); int cheats_available(); void cheats_scan(int mode); From 9fc5f10cc3ad3210c242ddd44d37a2b8d94d251b Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Thu, 28 May 2026 09:44:33 +0800 Subject: [PATCH 5/5] Embed Zaparoo Main capability marker --- support/zaparoo/main_capabilities.cpp | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 support/zaparoo/main_capabilities.cpp diff --git a/support/zaparoo/main_capabilities.cpp b/support/zaparoo/main_capabilities.cpp new file mode 100644 index 000000000..a75d1edba --- /dev/null +++ b/support/zaparoo/main_capabilities.cpp @@ -0,0 +1,5 @@ +extern "C" __attribute__((used)) +const char zaparoo_main_capabilities[] = + "ZAPAROO_MAIN_CAPABILITIES:" + "{\"schema\":1,\"id\":\"zaparoo-main\",\"version\":\"" VDATE "\"," + "\"capabilities\":{\"cheat_cmd\":1}}";