device info

This commit is contained in:
2026-05-04 17:57:35 +03:00
parent 4a5f1d4d07
commit eef7568185
5 changed files with 235 additions and 1 deletions

View File

@@ -2,7 +2,6 @@
- make `computer` component use callbacks - make `computer` component use callbacks
- finish tmpfs (rework the whole thing) - finish tmpfs (rework the whole thing)
- device info
- userdata support - userdata support
# To re-evaluate # To re-evaluate

View File

@@ -299,6 +299,27 @@ fail:
return 0; return 0;
} }
static int luaArch_computer_getDeviceInfo(lua_State *L) {
luaArch *arch = luaArch_from(L);
nn_Computer *C = arch->computer;
lua_createtable(L, 0, 0);
for(size_t i = 0;; i++) {
const char *devAddr = nn_deviceInfoAt(C, i);
if(devAddr == NULL) break;
size_t len;
const nn_DeviceField *fields = nn_getDeviceInfo(C, i, &len);
lua_pushstring(L, devAddr);
lua_createtable(L, 0, len);
for(size_t j = 0; j < len; j++) {
lua_pushstring(L, fields[j].name);
lua_pushstring(L, fields[j].value);
lua_settable(L, -3);
}
lua_settable(L, -3);
}
return 1;
}
static int luaArch_component_list(lua_State *L) { static int luaArch_component_list(lua_State *L) {
luaArch *arch = luaArch_from(L); luaArch *arch = luaArch_from(L);
lua_createtable(L, 64, 0); lua_createtable(L, 64, 0);
@@ -613,6 +634,8 @@ static void luaArch_loadEnv(lua_State *L) {
lua_setfield(L, computer, "pushSignal"); lua_setfield(L, computer, "pushSignal");
lua_pushcfunction(L, luaArch_computer_popSignal); lua_pushcfunction(L, luaArch_computer_popSignal);
lua_setfield(L, computer, "popSignal"); lua_setfield(L, computer, "popSignal");
lua_pushcfunction(L, luaArch_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);
int component = lua_gettop(L); int component = lua_gettop(L);

View File

@@ -514,6 +514,18 @@ int main(int argc, char **argv) {
nn_setTmpAddress(c, nn_getComponentAddress(tmpfs)); nn_setTmpAddress(c, nn_getComponentAddress(tmpfs));
nn_CommonDeviceInfo cinfo;
nn_clearCommonDeviceInfo(&cinfo);
cinfo.CLASS = NN_DEVICECLASS_SYSTEM;
cinfo.DESC = "The main computer";
cinfo.VENDOR = "NeoNucleus Inc.";
cinfo.PRODUCT = "NeoComputer";
cinfo.VERSION = "0.-1.0";
cinfo.CLOCK = "1 MHz";
cinfo.CAPACITY = "10 kJ";
nn_addCommonDeviceInfo(c, nn_getComputerAddress(c), cinfo);
nn_mountComponent(c, screen, -1, false); nn_mountComponent(c, screen, -1, false);
nn_mountComponent(c, ocelotCard, -1, false); nn_mountComponent(c, ocelotCard, -1, false);
nn_mountComponent(c, tmpfs, -1, false); nn_mountComponent(c, tmpfs, -1, false);

View File

@@ -1030,6 +1030,40 @@ typedef struct nn_Signal {
nn_Value *values; nn_Value *values;
} nn_Signal; } nn_Signal;
typedef struct nn_DeviceInfoEntry {
const char *address;
nn_Arena arena;
size_t len;
nn_DeviceField *fields;
} nn_DeviceInfoEntry;
typedef struct nn_DeviceInfoArray {
nn_DeviceInfoEntry *entries;
size_t len;
size_t cap;
size_t limit;
} nn_DeviceInfoArray;
nn_Exit nn_resizeDeviceInfoArray(nn_Context *ctx, nn_DeviceInfoArray *arr, size_t capNeeded) {
if(capNeeded > arr->limit) return NN_ELIMIT;
size_t newCap = arr->cap;
// enlarging
while(capNeeded > newCap) {
if(newCap == 0) newCap = 1;
else newCap *= 2;
}
// shrinking
while(capNeeded <= newCap/2 && newCap > 0) {
newCap /= 2;
}
if(newCap == arr->cap) return NN_OK;
nn_DeviceInfoEntry *newEntries = nn_realloc(ctx, arr->entries, sizeof(nn_DeviceInfoEntry) * arr->cap, sizeof(nn_DeviceInfoEntry) * newCap);
if(newEntries == NULL) return NN_ENOMEM;
arr->entries = newEntries;
arr->cap = newCap;
return NN_OK;
}
typedef struct nn_Computer { typedef struct nn_Computer {
nn_ComputerState state; nn_ComputerState state;
nn_Universe *universe; nn_Universe *universe;
@@ -1044,6 +1078,7 @@ typedef struct nn_Computer {
size_t callBudget; size_t callBudget;
size_t totalCallBudget; size_t totalCallBudget;
nn_HashMap components; nn_HashMap components;
nn_DeviceInfoArray deviceInfo;
double totalEnergy; double totalEnergy;
size_t totalMemory; size_t totalMemory;
double creationTimestamp; double creationTimestamp;
@@ -1169,6 +1204,11 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
return NULL; return NULL;
} }
c->deviceInfo.entries = NULL;
c->deviceInfo.len = 0;
c->deviceInfo.cap = 0;
c->deviceInfo.limit = maxDevices;
c->totalEnergy = 500; c->totalEnergy = 500;
c->env.handler = nn_default_envHandler; c->env.handler = nn_default_envHandler;
c->totalMemory = totalMemory; c->totalMemory = totalMemory;
@@ -1264,6 +1304,97 @@ void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env) {
computer->env = env; computer->env = env;
} }
const char *nn_deviceInfoAt(nn_Computer *computer, size_t idx) {
return idx < computer->deviceInfo.len ? computer->deviceInfo.entries[idx].address : NULL;
}
const nn_DeviceField *nn_getDeviceInfo(nn_Computer *computer, size_t idx, size_t *fieldCount) {
nn_DeviceInfoEntry entry = computer->deviceInfo.entries[idx];
*fieldCount = entry.len;
return entry.fields;
}
nn_Exit nn_addDeviceInfo(nn_Computer *computer, const char *addr, const nn_DeviceField *fields) {
size_t len = 0;
while(fields[len].name != NULL) len++;
return nn_addDeviceInfoL(computer, addr, fields, len);
}
nn_Exit nn_addDeviceInfoL(nn_Computer *computer, const char *addr, const nn_DeviceField *fields, size_t fieldCount) {
// We remove NULL values for simplicity in some emulators
size_t len = 0;
for(size_t i = 0; i < fieldCount; i++) {
if(fields[i].value != NULL) len++;
}
nn_Context *ctx = &computer->universe->ctx;
nn_Arena arena;
nn_arinit(&arena, ctx);
nn_Exit e = nn_resizeDeviceInfoArray(ctx, &computer->deviceInfo, computer->deviceInfo.len + 1);
if(e) goto fail;
nn_DeviceInfoEntry entry;
entry.len = len;
entry.address = nn_arstrdup(&arena, addr);
if(entry.address == NULL) goto fail;
entry.fields = nn_aralloc(&arena, sizeof(nn_DeviceField) * len);
if(entry.fields == NULL) goto fail;
size_t j = 0;
for(size_t i = 0; i < fieldCount; i++) {
nn_DeviceField f = fields[i];
if(f.value == NULL) continue;
f.name = nn_arstrdup(&arena, f.name);
if(f.name == NULL) goto fail;
f.value = nn_arstrdup(&arena, f.value);
if(f.value == NULL) goto fail;
entry.fields[j] = f;
j++;
}
entry.arena = arena;
computer->deviceInfo.entries[computer->deviceInfo.len] = entry;
computer->deviceInfo.len++;
return NN_OK;
fail:
nn_ardestroy(&arena);
return e;
}
nn_Exit nn_addCommonDeviceInfo(nn_Computer *computer, const char *addr, nn_CommonDeviceInfo info) {
// NULL value is ignored by addDeviceInfoL
nn_DeviceField fields[] = {
{NN_DEVICEATTR_CLASS, info.CLASS},
{NN_DEVICEATTR_DESC, info.DESC},
{NN_DEVICEATTR_VENDOR, info.VENDOR},
{NN_DEVICEATTR_PRODUCT, info.PRODUCT},
{NN_DEVICEATTR_VERSION, info.VERSION},
{NN_DEVICEATTR_SERIAL, info.SERIAL},
{NN_DEVICEATTR_CAPACITY, info.CAPACITY},
{NN_DEVICEATTR_SIZE, info.SIZE},
{NN_DEVICEATTR_CLOCK, info.CLOCK},
{NN_DEVICEATTR_WIDTH, info.WIDTH},
{NULL, NULL},
};
return nn_addDeviceInfo(computer, addr, fields);
}
// Sets every field to NULL.
void nn_clearCommonDeviceInfo(nn_CommonDeviceInfo *info) {
info->CLASS = NULL;
info->DESC = NULL;
info->VENDOR = NULL;
info->PRODUCT = NULL;
info->VERSION = NULL;
info->SERIAL = NULL;
info->CAPACITY = NULL;
info->SIZE = NULL;
info->CLOCK = NULL;
info->WIDTH = NULL;
}
bool nn_removeDeviceInfo(nn_Computer *computer, const char *addr);
void nn_beepComputer(nn_Computer *computer, nn_Beep beep) { void nn_beepComputer(nn_Computer *computer, nn_Beep beep) {
if(beep.duration < 0) beep.duration = 0; if(beep.duration < 0) beep.duration = 0;
nn_EnvironmentRequest req; nn_EnvironmentRequest req;
@@ -1289,6 +1420,12 @@ void nn_destroyComputer(nn_Computer *computer) {
nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED); nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED);
nn_dropComponent(c->comp); nn_dropComponent(c->comp);
} }
for(size_t i = 0; i < computer->deviceInfo.len; i++) {
nn_ardestroy(&computer->deviceInfo.entries[i].arena);
}
nn_free(ctx, computer->deviceInfo.entries, sizeof(nn_DeviceInfoEntry) * computer->deviceInfo.cap);
nn_destroyLock(ctx, computer->lock); nn_destroyLock(ctx, computer->lock);
nn_hashDeinit(&computer->components); nn_hashDeinit(&computer->components);
if(computer->tmpaddress != NULL) nn_strfree(ctx, computer->tmpaddress); if(computer->tmpaddress != NULL) nn_strfree(ctx, computer->tmpaddress);

View File

@@ -455,6 +455,69 @@ void nn_forceCrashComputer(nn_Computer *computer, const char *s);
bool nn_isComputerOn(nn_Computer *computer); bool nn_isComputerOn(nn_Computer *computer);
void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env); void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env);
// Device information
// Standard device attribute fields
#define NN_DEVICEATTR_CLASS "class"
#define NN_DEVICEATTR_DESC "description"
#define NN_DEVICEATTR_VENDOR "vendor"
#define NN_DEVICEATTR_PRODUCT "product"
#define NN_DEVICEATTR_VERSION "version"
#define NN_DEVICEATTR_SERIAL "serial"
#define NN_DEVICEATTR_CAPACITY "capacity"
#define NN_DEVICEATTR_SIZE "size"
#define NN_DEVICEATTR_CLOCK "clock"
#define NN_DEVICEATTR_WIDTH "width"
// Standard device classes
#define NN_DEVICECLASS_SYSTEM "system"
#define NN_DEVICECLASS_BRIDGE "bridge"
#define NN_DEVICECLASS_MEMORY "memory"
#define NN_DEVICECLASS_PROCESSOR "processor"
#define NN_DEVICECLASS_ADDRESS "address"
#define NN_DEVICECLASS_STORAGE "storage"
#define NN_DEVICECLASS_DISK "disk"
#define NN_DEVICECLASS_TAPE "tape"
#define NN_DEVICECLASS_BUS "bus"
#define NN_DEVICECLASS_NETWORK "network"
#define NN_DEVICECLASS_DISPLAY "display"
#define NN_DEVICECLASS_INPUT "input"
#define NN_DEVICECLASS_PRINTER "printer"
#define NN_DEVICECLASS_MULTIMEDIA "multimedia"
#define NN_DEVICECLASS_COMMUNICATION "communication"
#define NN_DEVICECLASS_POWER "power"
#define NN_DEVICECLASS_VOLUME "volume"
#define NN_DEVICECLASS_GENERIC "generic"
typedef struct nn_DeviceField {
const char *name;
const char *value;
} nn_DeviceField;
typedef struct nn_CommonDeviceInfo {
const char *CLASS;
const char *DESC;
const char *VENDOR;
const char *PRODUCT;
const char *VERSION;
const char *SERIAL;
const char *CAPACITY;
const char *SIZE;
const char *CLOCK;
const char *WIDTH;
} nn_CommonDeviceInfo;
const char *nn_deviceInfoAt(nn_Computer *computer, size_t idx);
const nn_DeviceField *nn_getDeviceInfo(nn_Computer *computer, size_t idx, size_t *fieldCount);
nn_Exit nn_addDeviceInfo(nn_Computer *computer, const char *addr, const nn_DeviceField *fields);
nn_Exit nn_addDeviceInfoL(nn_Computer *computer, const char *addr, const nn_DeviceField *fields, size_t fieldCount);
nn_Exit nn_addCommonDeviceInfo(nn_Computer *computer, const char *addr, nn_CommonDeviceInfo info);
// Sets every field to NULL.
void nn_clearCommonDeviceInfo(nn_CommonDeviceInfo *info);
bool nn_removeDeviceInfo(nn_Computer *computer, const char *addr);
void nn_beepComputer(nn_Computer *computer, nn_Beep beep); void nn_beepComputer(nn_Computer *computer, nn_Beep beep);
// get the userdata pointer // get the userdata pointer