device info
This commit is contained in:
1
TODO.md
1
TODO.md
@@ -2,7 +2,6 @@
|
||||
|
||||
- make `computer` component use callbacks
|
||||
- finish tmpfs (rework the whole thing)
|
||||
- device info
|
||||
- userdata support
|
||||
|
||||
# To re-evaluate
|
||||
|
||||
@@ -299,6 +299,27 @@ fail:
|
||||
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) {
|
||||
luaArch *arch = luaArch_from(L);
|
||||
lua_createtable(L, 64, 0);
|
||||
@@ -613,6 +634,8 @@ static void luaArch_loadEnv(lua_State *L) {
|
||||
lua_setfield(L, computer, "pushSignal");
|
||||
lua_pushcfunction(L, luaArch_computer_popSignal);
|
||||
lua_setfield(L, computer, "popSignal");
|
||||
lua_pushcfunction(L, luaArch_computer_getDeviceInfo);
|
||||
lua_setfield(L, computer, "getDeviceInfo");
|
||||
lua_setglobal(L, "computer");
|
||||
lua_createtable(L, 0, 10);
|
||||
int component = lua_gettop(L);
|
||||
|
||||
12
src/main.c
12
src/main.c
@@ -514,6 +514,18 @@ int main(int argc, char **argv) {
|
||||
|
||||
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, ocelotCard, -1, false);
|
||||
nn_mountComponent(c, tmpfs, -1, false);
|
||||
|
||||
137
src/neonucleus.c
137
src/neonucleus.c
@@ -1030,6 +1030,40 @@ typedef struct nn_Signal {
|
||||
nn_Value *values;
|
||||
} 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 {
|
||||
nn_ComputerState state;
|
||||
nn_Universe *universe;
|
||||
@@ -1044,6 +1078,7 @@ typedef struct nn_Computer {
|
||||
size_t callBudget;
|
||||
size_t totalCallBudget;
|
||||
nn_HashMap components;
|
||||
nn_DeviceInfoArray deviceInfo;
|
||||
double totalEnergy;
|
||||
size_t totalMemory;
|
||||
double creationTimestamp;
|
||||
@@ -1169,6 +1204,11 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->deviceInfo.entries = NULL;
|
||||
c->deviceInfo.len = 0;
|
||||
c->deviceInfo.cap = 0;
|
||||
c->deviceInfo.limit = maxDevices;
|
||||
|
||||
c->totalEnergy = 500;
|
||||
c->env.handler = nn_default_envHandler;
|
||||
c->totalMemory = totalMemory;
|
||||
@@ -1264,6 +1304,97 @@ void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment 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) {
|
||||
if(beep.duration < 0) beep.duration = 0;
|
||||
nn_EnvironmentRequest req;
|
||||
@@ -1289,6 +1420,12 @@ void nn_destroyComputer(nn_Computer *computer) {
|
||||
nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED);
|
||||
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_hashDeinit(&computer->components);
|
||||
if(computer->tmpaddress != NULL) nn_strfree(ctx, computer->tmpaddress);
|
||||
|
||||
@@ -455,6 +455,69 @@ void nn_forceCrashComputer(nn_Computer *computer, const char *s);
|
||||
bool nn_isComputerOn(nn_Computer *computer);
|
||||
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);
|
||||
|
||||
// get the userdata pointer
|
||||
|
||||
Reference in New Issue
Block a user