gamebook: load expanded books from PSRAM
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
|
||||||
#include "display_ui.h"
|
#include "display_ui.h"
|
||||||
#include "media_manager.h"
|
#include "media_manager.h"
|
||||||
@@ -17,7 +18,7 @@ static const char *TAG = "gamebook";
|
|||||||
|
|
||||||
#define GAMEBOOK_DIR "/sdcard/gamebook"
|
#define GAMEBOOK_DIR "/sdcard/gamebook"
|
||||||
#define LIBRARY_JSON GAMEBOOK_DIR "/library.json"
|
#define LIBRARY_JSON GAMEBOOK_DIR "/library.json"
|
||||||
#define JSON_MAX (64 * 1024) /* per-file JSON sanity cap */
|
#define JSON_MAX (256 * 1024) /* expanded books are ~80 KB of JSON */
|
||||||
#define LIB_MAX 6 /* matches the display tile grid */
|
#define LIB_MAX 6 /* matches the display tile grid */
|
||||||
|
|
||||||
typedef enum { GB_OFF, GB_LIBRARY, GB_STORY } gb_mode_t;
|
typedef enum { GB_OFF, GB_LIBRARY, GB_STORY } gb_mode_t;
|
||||||
@@ -39,6 +40,10 @@ static volatile gb_mode_t s_mode = GB_OFF;
|
|||||||
|
|
||||||
bool gamebook_active(void) { return s_mode != GB_OFF; }
|
bool gamebook_active(void) { return s_mode != GB_OFF; }
|
||||||
|
|
||||||
|
/* PSRAM allocators for cJSON — book trees are large (see gamebook_init). */
|
||||||
|
static void *gb_malloc(size_t sz) { return heap_caps_malloc(sz, MALLOC_CAP_SPIRAM); }
|
||||||
|
static void gb_free(void *p) { heap_caps_free(p); }
|
||||||
|
|
||||||
/* Read a whole JSON file from the SD into a cJSON tree (caller frees). */
|
/* Read a whole JSON file from the SD into a cJSON tree (caller frees). */
|
||||||
static cJSON *load_json(const char *path)
|
static cJSON *load_json(const char *path)
|
||||||
{
|
{
|
||||||
@@ -48,13 +53,13 @@ static cJSON *load_json(const char *path)
|
|||||||
long sz = ftell(f);
|
long sz = ftell(f);
|
||||||
rewind(f);
|
rewind(f);
|
||||||
if (sz <= 0 || sz > JSON_MAX) { fclose(f); ESP_LOGW(TAG, "%s size %ld", path, sz); return NULL; }
|
if (sz <= 0 || sz > JSON_MAX) { fclose(f); ESP_LOGW(TAG, "%s size %ld", path, sz); return NULL; }
|
||||||
char *buf = malloc((size_t)sz + 1);
|
char *buf = heap_caps_malloc((size_t)sz + 1, MALLOC_CAP_SPIRAM);
|
||||||
if (!buf) { fclose(f); return NULL; }
|
if (!buf) { fclose(f); return NULL; }
|
||||||
size_t rd = fread(buf, 1, (size_t)sz, f);
|
size_t rd = fread(buf, 1, (size_t)sz, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
buf[rd] = '\0';
|
buf[rd] = '\0';
|
||||||
cJSON *root = cJSON_Parse(buf);
|
cJSON *root = cJSON_Parse(buf);
|
||||||
free(buf);
|
heap_caps_free(buf);
|
||||||
if (!root) ESP_LOGW(TAG, "malformed JSON: %s", path);
|
if (!root) ESP_LOGW(TAG, "malformed JSON: %s", path);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
@@ -285,6 +290,14 @@ void gamebook_stop(void)
|
|||||||
|
|
||||||
void gamebook_init(void)
|
void gamebook_init(void)
|
||||||
{
|
{
|
||||||
|
/* Keep the large book trees in PSRAM — an expanded book is ~80 KB of JSON,
|
||||||
|
* whose parsed node tree would exhaust the internal heap on this firmware. */
|
||||||
|
static cJSON_Hooks hooks = {
|
||||||
|
.malloc_fn = gb_malloc,
|
||||||
|
.free_fn = gb_free,
|
||||||
|
};
|
||||||
|
cJSON_InitHooks(&hooks);
|
||||||
|
|
||||||
/* Only register the pad hook here — the SD and media_manager aren't up yet
|
/* Only register the pad hook here — the SD and media_manager aren't up yet
|
||||||
* at this point in boot. main.c calls gamebook_start() once they are, to
|
* at this point in boot. main.c calls gamebook_start() once they are, to
|
||||||
* boot into the library. */
|
* boot into the library. */
|
||||||
|
|||||||
Reference in New Issue
Block a user