device info

This commit is contained in:
IonutParau 2025-07-29 16:41:22 +02:00
parent 087fd1e9b3
commit 9e33d5a1d2
9 changed files with 243 additions and 6 deletions

View File

@ -4,6 +4,8 @@
`nn_<class>_<method>` for functions related to "classes", `nn_<class>_<method>` for functions related to "classes",
`nn_<function>` for static functions, `nn_<function>` for static functions,
`nn_<type>_t` for types. `nn_<type>_t` for types.
- Get rid of `nn_address`
- Make a lot more stuff const
- Rework to API to be much more future-proof to reduce potential breaking changes. - Rework to API to be much more future-proof to reduce potential breaking changes.
# Parity with Vanilla OC (only the stuff that makes sense for an emulator) # Parity with Vanilla OC (only the stuff that makes sense for an emulator)
@ -13,7 +15,6 @@
- `data` component (with error correction codes and maybe synthesizing audio) - `data` component (with error correction codes and maybe synthesizing audio)
- `redstone` component - `redstone` component
- `internet` component - `internet` component
- `computer.getDeviceInfo()`, and subsequently, component device information
- `computer.beep(frequency?: number, duration?: number, volume?: number)`, frequency between 20 and 2000 Hz, duration up to 5 seconds, volume from 0 to 1. - `computer.beep(frequency?: number, duration?: number, volume?: number)`, frequency between 20 and 2000 Hz, duration up to 5 seconds, volume from 0 to 1.
# Bugfixes # Bugfixes
@ -39,6 +40,7 @@
# Internal changes # Internal changes
- use more arenas!!!!!!!
- make sure OOMs are recoverable - make sure OOMs are recoverable
- rework some interfaces to use pre-allocated or stack-allocated memory more - rework some interfaces to use pre-allocated or stack-allocated memory more
- use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging - use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging

View File

@ -27,6 +27,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
"src/resource.c", "src/resource.c",
"src/component.c", "src/component.c",
"src/computer.c", "src/computer.c",
"src/deviceInfo.c",
"src/universe.c", "src/universe.c",
"src/unicode.c", "src/unicode.c",
// components // components

View File

@ -25,6 +25,8 @@ nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_archit
nn_dealloc(alloc, c, sizeof(nn_computer)); nn_dealloc(alloc, c, sizeof(nn_computer));
return NULL; return NULL;
} }
// TODO: handle OOM
c->deviceInfo = nn_newDeviceInfoList(&universe->ctx, 16);
c->timeOffset = nn_getTime(universe); c->timeOffset = nn_getTime(universe);
c->supportedArchCount = 0; c->supportedArchCount = 0;
c->argc = 0; c->argc = 0;
@ -646,3 +648,7 @@ const char *nn_resource_nextMethodInfo(nn_computer *computer, nn_size_t id, cons
} }
return NULL; return NULL;
} }
nn_deviceInfoList_t *nn_getComputerDeviceInfoList(nn_computer *computer) {
return computer->deviceInfo;
}

View File

@ -50,6 +50,7 @@ typedef struct nn_computer {
double callBudget; double callBudget;
nn_size_t rid; nn_size_t rid;
nn_resource_t resources[NN_MAX_CONCURRENT_RESOURCES]; nn_resource_t resources[NN_MAX_CONCURRENT_RESOURCES];
nn_deviceInfoList_t *deviceInfo;
} nn_computer; } nn_computer;
#endif #endif

119
src/deviceInfo.c Normal file
View File

@ -0,0 +1,119 @@
#include "neonucleus.h"
typedef struct nn_deviceInfoPair_t {
char *key;
char *value;
} nn_deviceInfoPair_t;
typedef struct nn_deviceInfo_t {
nn_deviceInfoPair_t *pairs;
nn_size_t len;
nn_size_t capacity;
char *address;
nn_Alloc alloc;
} nn_deviceInfo_t;
typedef struct nn_deviceInfoList_t {
nn_Context ctx;
nn_deviceInfo_t *info;
nn_size_t len;
nn_size_t cap;
} nn_deviceInfoList_t;
nn_deviceInfoList_t *nn_newDeviceInfoList(nn_Context *ctx, nn_size_t preallocate) {
nn_Alloc *alloc = &ctx->allocator;
nn_deviceInfoList_t *list = nn_alloc(alloc, sizeof(nn_deviceInfoList_t));
if(list == NULL) return NULL;
list->ctx = *ctx;
list->len = 0;
list->cap = preallocate;
list->info = nn_alloc(alloc, sizeof(nn_deviceInfo_t) * list->cap);
if(list->info == NULL) {
nn_dealloc(alloc, list, sizeof(nn_deviceInfoList_t));
return NULL;
}
return list;
}
static void nn_deleteDeviceInfo(nn_Context *ctx, nn_deviceInfo_t *info) {
nn_Alloc *alloc = &ctx->allocator;
nn_deallocStr(alloc, info->address);
nn_dealloc(alloc, info->pairs, sizeof(nn_deviceInfoPair_t) * info->capacity);
}
void nn_deleteDeviceInfoList(nn_deviceInfoList_t *list) {
for(nn_size_t i = 0; i < list->len; i++) {
nn_deleteDeviceInfo(&list->ctx, &list->info[i]);
}
nn_Alloc alloc = list->ctx.allocator;
nn_dealloc(&alloc, list->info, sizeof(nn_deviceInfo_t) * list->cap);
nn_dealloc(&alloc, list, sizeof(nn_deviceInfoList_t));
}
nn_deviceInfo_t *nn_addDeviceInfo(nn_deviceInfoList_t *list, nn_address address, nn_size_t maxKeys) {
if(list->len == list->cap) {
nn_size_t neededCap = list->cap;
if(neededCap < 1) neededCap = 1;
while(neededCap < (list->len + 1)) neededCap *= 2;
nn_deviceInfo_t *newBuf = nn_resize(&list->ctx.allocator, list->info, sizeof(nn_deviceInfo_t) * list->cap, sizeof(nn_deviceInfo_t) * neededCap);
if(newBuf == NULL) return NULL;
list->cap = neededCap;
list->info = newBuf;
}
nn_deviceInfoPair_t *pairs = nn_alloc(&list->ctx.allocator, sizeof(nn_deviceInfoPair_t) * maxKeys);
if(pairs == NULL) return NULL;
nn_size_t i = list->len;
list->info[i] = (nn_deviceInfo_t) {
.alloc = list->ctx.allocator,
.pairs = pairs,
.len = 0,
.address = address == NULL ? nn_randomUUID(&list->ctx) : nn_strdup(&list->ctx.allocator, address), // TODO: handle OOM
.capacity = maxKeys,
};
list->len++;
return list->info + i;
}
void nn_removeDeviceInfo(nn_deviceInfoList_t *list, const char *key);
nn_bool_t nn_registerDeviceKey(nn_deviceInfo_t *deviceInfo, const char *key, const char *value) {
if(deviceInfo->len == deviceInfo->capacity) return false;
nn_size_t i = deviceInfo->len;
nn_Alloc *alloc = &deviceInfo->alloc;
// TODO: handle OOM
deviceInfo->pairs[i].key = nn_strdup(alloc, key);
deviceInfo->pairs[i].value = nn_strdup(alloc, value);
deviceInfo->len++;
return true;
}
nn_deviceInfo_t *nn_getDeviceInfoAt(nn_deviceInfoList_t *list, nn_size_t idx) {
if(idx >= list->len) return NULL;
return &list->info[idx];
}
const char *nn_getDeviceInfoAddress(nn_deviceInfo_t *deviceInfo) {
return deviceInfo->address;
}
nn_size_t nn_getDeviceCount(nn_deviceInfoList_t *list) {
return list->len;
}
const char *nn_iterateDeviceInfoKeys(nn_deviceInfo_t *deviceInfo, nn_size_t idx, const char **value) {
if(idx >= deviceInfo->len) return NULL;
nn_deviceInfoPair_t pair = deviceInfo->pairs[idx];
if(value != NULL) *value = pair.value;
return pair.key;
}
nn_size_t nn_getDeviceKeyCount(nn_deviceInfo_t *deviceInfo) {
return deviceInfo->len;
}

View File

@ -811,6 +811,21 @@ int main(int argc, char **argv) {
double interval = 1.0/tps; double interval = 1.0/tps;
double totalTime = 0; double totalTime = 0;
nn_deviceInfoList_t *list = nn_getComputerDeviceInfoList(computer);
nn_deviceInfo_t *theRamStick = nn_addDeviceInfo(list, NULL, 8);
nn_registerDeviceKey(theRamStick, NN_DEVICEINFO_KEY_CLASS, NN_DEVICEINFO_CLASS_RAM);
nn_registerDeviceKey(theRamStick, NN_DEVICEINFO_KEY_CAPACITY, "4MiB");
nn_registerDeviceKey(theRamStick, NN_DEVICEINFO_KEY_DESCRIPTION, "Volatile storage device");
nn_registerDeviceKey(theRamStick, NN_DEVICEINFO_KEY_PRODUCT, "RAM 1:5");
nn_registerDeviceKey(theRamStick, NN_DEVICEINFO_KEY_VENDOR, "NeoComputers Technologies L.L.C.");
nn_deviceInfo_t *theCPU = nn_addDeviceInfo(list, NULL, 8);
nn_registerDeviceKey(theCPU, NN_DEVICEINFO_KEY_CLASS, NN_DEVICEINFO_CLASS_CPU);
nn_registerDeviceKey(theCPU, NN_DEVICEINFO_KEY_DESCRIPTION, "Processor");
nn_registerDeviceKey(theCPU, NN_DEVICEINFO_KEY_PRODUCT, "Cryzen 9 6900XXL");
nn_registerDeviceKey(theCPU, NN_DEVICEINFO_KEY_VENDOR, "NeoComputers Technologies L.L.C.");
while(true) { while(true) {
if(WindowShouldClose()) break; if(WindowShouldClose()) break;
nn_setEnergyInfo(computer, 5000, 5000); nn_setEnergyInfo(computer, 5000, 5000);

View File

@ -409,6 +409,48 @@ void *nn_queryUserdata(nn_universe *universe, const char *name);
void nn_storeUserdata(nn_universe *universe, const char *name, void *data); void nn_storeUserdata(nn_universe *universe, const char *name, void *data);
double nn_getTime(nn_universe *universe); double nn_getTime(nn_universe *universe);
// Device info
typedef struct nn_deviceInfoList_t nn_deviceInfoList_t;
typedef struct nn_deviceInfo_t nn_deviceInfo_t;
// Common / standard keys
#define NN_DEVICEINFO_KEY_CLASS "class"
#define NN_DEVICEINFO_KEY_VENDOR "vendor"
#define NN_DEVICEINFO_KEY_PRODUCT "product"
#define NN_DEVICEINFO_KEY_CAPACITY "capacity"
#define NN_DEVICEINFO_KEY_CLOCK "clock"
#define NN_DEVICEINFO_KEY_DESCRIPTION "description"
// Common / standard values
#define NN_DEVICEINFO_CLASS_INPUT "input"
#define NN_DEVICEINFO_CLASS_RAM "memory"
#define NN_DEVICEINFO_CLASS_ROM "memory" // not a mistake, they both use memory
#define NN_DEVICEINFO_CLASS_CPU "processor" // also used by data card
#define NN_DEVICEINFO_CLASS_DATA "processor" // also used by data card
#define NN_DEVICEINFO_CLASS_GPU "display" // not a mistake, it and screen have the same class
#define NN_DEVICEINFO_CLASS_SCREEN "display"
#define NN_DEVICEINFO_CLASS_COMPUTER "system"
#define NN_DEVICEINFO_CLASS_STORAGE "volume"
#define NN_DEVICEINFO_CLASS_INTERNET "communication"
#define NN_DEVICEINFO_CLASS_REDSTONE "communication" // why do they use the same one? idfk
#define NN_DEVICEINFO_CLASS_MODEM "network"
#define NN_DEVICEINFO_CLASS_TUNNEL "network"
#define NN_DEVICEINFO_CLASS_GENERIC "generic"
nn_deviceInfoList_t *nn_newDeviceInfoList(nn_Context *ctx, nn_size_t preallocate);
void nn_deleteDeviceInfoList(nn_deviceInfoList_t *deviceInfoList);
nn_deviceInfo_t *nn_addDeviceInfo(nn_deviceInfoList_t *list, nn_address address, nn_size_t maxKeys);
void nn_removeDeviceInfo(nn_deviceInfoList_t *list, const char *key);
nn_bool_t nn_registerDeviceKey(nn_deviceInfo_t *deviceInfo, const char *key, const char *value);
nn_deviceInfo_t *nn_getDeviceInfoAt(nn_deviceInfoList_t *list, nn_size_t idx);
nn_size_t nn_getDeviceCount(nn_deviceInfoList_t *list);
const char *nn_getDeviceInfoAddress(nn_deviceInfo_t *deviceInfo);
const char *nn_iterateDeviceInfoKeys(nn_deviceInfo_t *deviceInfo, nn_size_t idx, const char **value);
nn_size_t nn_getDeviceKeyCount(nn_deviceInfo_t *deviceInfo);
// Computer running states
nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_architecture *arch, void *userdata, nn_size_t memoryLimit, nn_size_t componentLimit); nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_architecture *arch, void *userdata, nn_size_t memoryLimit, nn_size_t componentLimit);
nn_universe *nn_getUniverse(nn_computer *computer); nn_universe *nn_getUniverse(nn_computer *computer);
int nn_tickComputer(nn_computer *computer); int nn_tickComputer(nn_computer *computer);
@ -436,6 +478,7 @@ void nn_callCost(nn_computer *computer, double cost);
double nn_getCallCost(nn_computer *computer); double nn_getCallCost(nn_computer *computer);
nn_bool_t nn_isOverworked(nn_computer *computer); nn_bool_t nn_isOverworked(nn_computer *computer);
void nn_triggerIndirect(nn_computer *computer); void nn_triggerIndirect(nn_computer *computer);
nn_deviceInfoList_t *nn_getComputerDeviceInfoList(nn_computer *computer);
/* The memory returned can be freed with nn_dealloc() */ /* The memory returned can be freed with nn_dealloc() */
char *nn_serializeProgram(nn_computer *computer, nn_Alloc *alloc, nn_size_t *len); char *nn_serializeProgram(nn_computer *computer, nn_Alloc *alloc, nn_size_t *len);
@ -1068,12 +1111,32 @@ void nn_hologram_fill(nn_hologram *hologram, int x, int z, int minY, int maxY, i
void nn_hologram_copy(nn_hologram *hologram, int x, int z, int sx, int sz, int tx, int tz); void nn_hologram_copy(nn_hologram *hologram, int x, int z, int sx, int sz, int tx, int tz);
float nn_hologram_getScale(nn_hologram *hologram); float nn_hologram_getScale(nn_hologram *hologram);
void nn_hologram_setScale(nn_hologram *hologram, float value); void nn_hologram_setScale(nn_hologram *hologram, float value);
void nn_hologram_getTranslation(nn_hologram *hologram, int *x, int *y, int *z); void nn_hologram_getTranslation(nn_hologram *hologram, double *x, double *y, double *z);
void nn_hologram_setTranslation(nn_hologram *hologram, int x, int y, int z); void nn_hologram_setTranslation(nn_hologram *hologram, double x, double y, double z);
int nn_hologram_maxDepth(nn_hologram *hologram); int nn_hologram_maxDepth(nn_hologram *hologram);
int nn_hologram_getPaletteColor(nn_hologram *hologram, int index); int nn_hologram_getPaletteColor(nn_hologram *hologram, int index);
int nn_hologram_setPaletteColor(nn_hologram *hologram, int index, int value); int nn_hologram_setPaletteColor(nn_hologram *hologram, int index, int value);
typedef struct nn_externalComputerTable_t {
void *userdata;
void (*deinit)(void *userdata);
nn_bool_t (*start)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
nn_bool_t (*stop)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
nn_bool_t (*isRunning)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
void (*beep)(void *userdata, nn_computer *requester, double freq, double duration, double volume, nn_errorbuf_t err);
void (*crash)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
nn_architecture *(*getArchitecture)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
nn_bool_t (*isRobot)(void *userdata, nn_computer *requester, nn_errorbuf_t err);
} nn_externalComputerTable_t;
typedef struct nn_externalComputer_t nn_externalComputer_t;
// An external computer is a computer component.
// It may refer to the current computer (counter-intuitively)
// It may exist when the computer it is refering too has no running state (aka is powered off)
nn_externalComputer_t *nn_newExternalComputer(nn_Context *ctx, nn_externalComputerTable_t table);
#ifdef __cplusplus // c++ sucks #ifdef __cplusplus // c++ sucks
} }
#endif #endif

View File

@ -236,9 +236,7 @@ local libcomputer = {
until computer.uptime() >= deadline until computer.uptime() >= deadline
end, end,
beep = computer.beep, beep = computer.beep,
getDeviceInfo = function() getDeviceInfo = computer.getDeviceInfo,
return {} -- yup
end,
getProgramLocations = function() getProgramLocations = function()
return {} -- yup return {} -- yup
end, end,

View File

@ -339,6 +339,36 @@ static int testLuaArch_computer_setState(lua_State *L) {
return 1; return 1;
} }
static int testLuaArch_computer_getDeviceInfo(lua_State *L) {
nn_computer *c = testLuaArch_getComputer(L);
nn_deviceInfoList_t *list = nn_getComputerDeviceInfoList(c);
nn_size_t deviceCount = nn_getDeviceCount(list);
lua_createtable(L, 0, deviceCount);
int infoTable = lua_gettop(L);
for(nn_size_t i = 0; i < deviceCount; i++) {
nn_deviceInfo_t *info = nn_getDeviceInfoAt(list, i);
lua_createtable(L, 0, 16);
int deviceTable = lua_gettop(L);
nn_size_t j = 0;
while(true) {
const char *value = NULL;
const char *key = nn_iterateDeviceInfoKeys(info, j, &value);
j++;
if(key == NULL) break;
lua_pushstring(L, value);
lua_setfield(L, deviceTable, key);
}
lua_setfield(L, infoTable, nn_getDeviceInfoAddress(info));
}
return 1;
}
static int testLuaArch_component_list(lua_State *L) { static int testLuaArch_component_list(lua_State *L) {
nn_computer *c = testLuaArch_getComputer(L); nn_computer *c = testLuaArch_getComputer(L);
lua_createtable(L, 0, 10); lua_createtable(L, 0, 10);
@ -598,6 +628,8 @@ void testLuaArch_loadEnv(lua_State *L) {
lua_setfield(L, computer, "getState"); lua_setfield(L, computer, "getState");
lua_pushcfunction(L, testLuaArch_computer_setState); lua_pushcfunction(L, testLuaArch_computer_setState);
lua_setfield(L, computer, "setState"); lua_setfield(L, computer, "setState");
lua_pushcfunction(L, testLuaArch_computer_getDeviceInfo);
lua_setfield(L, computer, "getDeviceInfo");
lua_setglobal(L, "computer"); lua_setglobal(L, "computer");
lua_createtable(L, 0, 10); lua_createtable(L, 0, 10);