// os_playdate.c - OS module for Playdate // Provides system information and utilities for Playdate platform #include "cell.h" #include "pd_api.h" #include #include // Global Playdate API pointers - defined in main_playdate.c extern const struct playdate_sys *pd_sys; // cell_ns - nanoseconds since some epoch (used by scheduler) uint64_t cell_ns(void) { // Playdate provides milliseconds, convert to nanoseconds if (pd_sys) { unsigned int ms = pd_sys->getCurrentTimeMilliseconds(); return (uint64_t)ms * 1000000ULL; } return 0; } // cell_sleep - sleep for specified seconds void cell_sleep(double seconds) { if (pd_sys) { pd_sys->delay((uint32_t)(seconds * 1000)); } } JSC_CCALL(os_now, return number2js(js, cell_ns()); ) JSC_CCALL(os_sleep, double secs = js2number(js, argv[0]); cell_sleep(secs); ) static JSValue js_os_totalmem(JSContext *js, JSValue self, int argc, JSValue *argv) { // Playdate has 16MB RAM, but we don't have direct access to memory stats return JS_NewInt64(js, 16); // 16 MB } static JSValue js_os_platform(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NewString(js, "Playdate"); } static JSValue js_os_hostname(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NewString(js, "playdate"); } static JSValue js_os_arch(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NewString(js, "arm"); } static JSValue js_os_freemem(JSContext *js, JSValue self, int argc, JSValue *argv) { // No way to get free memory on Playdate return JS_NewInt64(js, 0); } static JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) { #if TARGET_EXTENSION if (pd_sys) { const struct PDInfo *info = pd_sys->getSystemInfo(); if (info) { char buf[32]; snprintf(buf, sizeof(buf), "%u", info->osversion); return JS_NewString(js, buf); } } #endif return JS_NewString(js, "unknown"); } JSC_CCALL(os_mallinfo, ret = JS_NewObject(js); ) static JSValue js_os_rusage(JSContext *js, JSValue self, int argc, JSValue *argv) { // No rusage on Playdate return JS_NewObject(js); } JSC_SCALL(os_system, // system() not available on Playdate ret = JS_NewInt32(js, -1); ) JSC_CCALL(os_exit, // Can't really exit on Playdate, but we can try exit(0); ) // dylib functions - not supported on Playdate static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_RaiseDisrupt(js, "dylib_open: not supported on Playdate"); } static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_RaiseDisrupt(js, "dylib_symbol: not supported on Playdate"); } static JSValue js_os_dylib_has_symbol(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NewBool(js, 0); } JSC_CCALL(os_print, size_t len; const char *str = JS_ToCStringLen(js, &len, argv[0]); if (pd_sys) { pd_sys->logToConsole("%.*s", (int)len, str); } JS_FreeCString(js, str); ) static JSValue js_os_load_internal(JSContext *js, JSValue self, int argc, JSValue *argv) { // No dlsym on Playdate - internal modules are linked statically return JS_NULL; } static JSValue js_os_internal_exists(JSContext *js, JSValue self, int argc, JSValue *argv) { return JS_NewBool(js, 0); } // Random number generation int randombytes(void *buf, size_t n) { // Playdate doesn't have a crypto RNG, use a simple PRNG seeded from time // This is NOT cryptographically secure! uint8_t *p = (uint8_t *)buf; static uint32_t seed = 0; if (seed == 0 && pd_sys) { seed = pd_sys->getCurrentTimeMilliseconds(); } for (size_t i = 0; i < n; i++) { seed = seed * 1103515245 + 12345; p[i] = (uint8_t)(seed >> 16); } return 0; } JSC_CCALL(os_random, return JS_NewFloat64(js, cell_random_fit()); ) JSC_CCALL(os_getenv, // No environment variables on Playdate return JS_NULL; ) static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, platform, 0), MIST_FUNC_DEF(os, arch, 0), MIST_FUNC_DEF(os, totalmem, 0), MIST_FUNC_DEF(os, freemem, 0), MIST_FUNC_DEF(os, hostname, 0), MIST_FUNC_DEF(os, version, 0), MIST_FUNC_DEF(os, now, 0), MIST_FUNC_DEF(os, rusage, 0), MIST_FUNC_DEF(os, mallinfo, 0), MIST_FUNC_DEF(os, system, 1), MIST_FUNC_DEF(os, exit, 0), MIST_FUNC_DEF(os, sleep, 1), MIST_FUNC_DEF(os, dylib_open, 1), MIST_FUNC_DEF(os, dylib_symbol, 2), MIST_FUNC_DEF(os, dylib_has_symbol, 2), MIST_FUNC_DEF(os, load_internal, 1), MIST_FUNC_DEF(os, internal_exists, 1), MIST_FUNC_DEF(os, print, 1), MIST_FUNC_DEF(os, random, 0), MIST_FUNC_DEF(os, getenv, 1), }; JSValue js_os_use(JSContext *js) { JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js, mod, js_os_funcs, countof(js_os_funcs)); return mod; }