diff --git a/TODO.md b/TODO.md index eab6658..00cc0a6 100644 --- a/TODO.md +++ b/TODO.md @@ -1,9 +1,10 @@ # For MVP functionality -- NCL computer states, as computers that can be turned on/off/beep/etc. +- add brightness to screens, which power usage scales with, each different tier has a different max brightness as well - write a tester OS, basically a menu with tests to run -- tmpfs (rework the whole thing) +- finish tmpfs (rework the whole thing) - device info +- finish `computer` components - userdata support # To re-evaluate diff --git a/src/main.c b/src/main.c index d22fa85..45495f2 100644 --- a/src/main.c +++ b/src/main.c @@ -458,6 +458,7 @@ int main(int argc, char **argv) { } nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); + nn_Component *wrappedC = nn_wrapComputer(c); if(showStats) { // collects stats nn_setEnergyHandler(c, NULL, ne_energy_accumulator); @@ -472,6 +473,7 @@ int main(int argc, char **argv) { //nn_setTmpAddress(c, nn_getComponentAddress(tmpfs)); + nn_mountComponent(c, wrappedC, 255); nn_mountComponent(c, screen, -1); nn_mountComponent(c, ocelotCard, -1); //nn_mountComponent(c, tmpfs, -1); @@ -495,6 +497,12 @@ int main(int argc, char **argv) { size_t scrw, scrh; ncl_getScreenViewport(scrbuf, &scrw, &scrh); + ncl_ScreenFlags scrflags = ncl_getScreenFlags(scrbuf); + if((scrflags & NCL_SCREEN_ON) == 0) { + ncl_unlockScreen(scrbuf); + goto skipDrawScreen; + } + int cheight = GetScreenHeight() / scrh; if(cheight != ncl_cellHeight(gc)) { ncl_destroyGlyphCache(gc); @@ -522,6 +530,7 @@ int main(int argc, char **argv) { ncl_unlockScreen(scrbuf); ncl_flushGlyphs(gc); } +skipDrawScreen: int statY = 10; if(sand.buf != NULL) { @@ -650,6 +659,7 @@ cleanup:; nn_dropComponent(screen); nn_dropComponent(gpuCard); nn_dropComponent(keyboard); + nn_dropComponent(wrappedC); // rip the universe nn_destroyUniverse(u); ncl_destroyGlyphCache(gc); diff --git a/src/ncomplib.c b/src/ncomplib.c index 9a66e9a..7c6e530 100644 --- a/src/ncomplib.c +++ b/src/ncomplib.c @@ -532,6 +532,7 @@ typedef struct ncl_ScreenState { ncl_ScreenPixel *pixels; ncl_ScreenFlags flags; size_t keyboardCount; + double brightness; char *keyboards[NCL_MAX_KEYBOARD]; } ncl_ScreenState; @@ -2269,11 +2270,12 @@ nn_Component *ncl_createScreen(nn_Universe *universe, const char *address, const screen->palette = palette; screen->resolvedPalette = resolvedPalette; screen->pixels = pixels; - screen->flags = 0; + screen->flags = NCL_SCREEN_ON; screen->depth = config->maxDepth; screen->viewportWidth = screen->width; screen->viewportHeight = screen->height; screen->keyboardCount = 0; + screen->brightness = 1; ncl_resetScreen(screen); @@ -3323,6 +3325,7 @@ const char *ncl_getKeyboard(ncl_ScreenState *state, } double ncl_getScreenEnergyUsage(ncl_ScreenState *state) { + if((state->flags & NCL_SCREEN_ON) == 0) return 0; double sum = 0; for(int y = 1; y <= state->viewportHeight; y++) { for(int x = 1; x <= state->viewportWidth; x++) { @@ -3336,6 +3339,14 @@ double ncl_getScreenEnergyUsage(ncl_ScreenState *state) { return sum; } +double ncl_getScreenBrightness(ncl_ScreenState *state) { + return state->brightness; +} + +void ncl_setScreenBrightness(ncl_ScreenState *state, double brightness) { + state->brightness = brightness; +} + // general stuff bool ncl_isNCLID(const char *type) { diff --git a/src/ncomplib.h b/src/ncomplib.h index 68718b9..7291ed3 100644 --- a/src/ncomplib.h +++ b/src/ncomplib.h @@ -344,5 +344,7 @@ void ncl_unmountKeyboard(ncl_ScreenState *state, const char *keyboardAddress); bool ncl_hasKeyboard(ncl_ScreenState *state, const char *keyboardAddress); const char *ncl_getKeyboard(ncl_ScreenState *state, size_t idx); double ncl_getScreenEnergyUsage(ncl_ScreenState *state); +double ncl_getScreenBrightness(ncl_ScreenState *state); +void ncl_setScreenBrightness(ncl_ScreenState *state, double brightness); #endif diff --git a/src/neonucleus.c b/src/neonucleus.c index b571d72..df8b08c 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -1219,7 +1219,7 @@ nn_Exit nn_startComputer(nn_Computer *computer) { nn_Exit err = computer->arch.handler(&req); if(err) { computer->state = NN_CRASHED; - nn_setErrorFromExit(computer, err); + if(err != NN_EBADCALL) nn_setErrorFromExit(computer, err); return err; } computer->archState = req.localState; @@ -3619,6 +3619,69 @@ nn_Exit nn_pushModemMessage(nn_Computer *C, const char *modemAddress, const char return nn_pushSignal(C, signalVals); } +nn_Computer *nn_fromWrappedComputer(nn_Component *component) { + if(nn_strcmp(component->internalID, "NN_WRAPPEDCOMPUTER") == 0) { + return component->state; + } + return NULL; +} + +nn_Exit nn_transferErrorFrom(nn_Exit exit, nn_Computer *from, nn_Computer *to) { + const char *err = nn_getError(from); + if(err != NULL) nn_setError(to, err); + return exit; +} + +typedef enum nn_CompNum { + NN_COMPNUM_START, + NN_COMPNUM_STOP, + NN_COMPNUM_ISRUNNING, + NN_COMPNUM_GETDEVICEINFO, + NN_COMPNUM_CRASH, + NN_COMPNUM_GETARCH, + NN_COMPNUM_ISROBOT, + NN_COMPNUM_BEEP, + + NN_COMPNUM_COUNT, +} nn_CompNum; + +static nn_Exit nn_computerHandler(nn_ComponentRequest *req) { + if(req->action == NN_COMP_DROP) return NN_OK; + if(req->action == NN_COMP_SIGNAL) return NN_OK; + nn_Computer *target = req->state; + nn_Computer *src = req->computer; + nn_CompNum method = req->methodIdx; + if(src) nn_setError(src, "computer: not implemented yet"); + return NN_EBADCALL; +} + +nn_Component *nn_wrapComputer(nn_Computer *computer) { + const nn_Method methods[NN_COMPNUM_COUNT] = { + [NN_COMPNUM_START] = {"start", "function(): boolean - Attempts to turn on the computer, will return false if it is already on or it failed", NN_INDIRECT}, + [NN_COMPNUM_STOP] = {"stop", "function(): boolean - Attempts to turn ooff the computer, will return false if it is already off or it failed", NN_INDIRECT}, + [NN_COMPNUM_ISRUNNING] = {"isRunning", "function(): boolean - Returns whether it is running or not", NN_INDIRECT}, + [NN_COMPNUM_GETDEVICEINFO] = {"getDeviceInfo", "function(): table> - Returns a table of device information for the computer", NN_INDIRECT}, + [NN_COMPNUM_CRASH] = {"crash", "function(error: string) - Will forcefully crash the computer, if it is running", NN_INDIRECT}, + [NN_COMPNUM_GETARCH] = {"getArchitecture", "function(): string - Get the architecture of the computer", NN_INDIRECT}, + [NN_COMPNUM_ISROBOT] = {"isRobot", "function(): boolean - Returns whether the computer is a robot", NN_INDIRECT}, + [NN_COMPNUM_BEEP] = {"beep", "function(frequency?: number, duration?: number, volume?: number) - Makes the computer make a beep sound", NN_INDIRECT}, + }; + + nn_Component *c = nn_createComponent(computer->universe, computer->address, "computer"); + if(c == NULL) return NULL; + nn_setComponentState(c, computer); + nn_setComponentHandler(c, nn_computerHandler); + if(nn_setComponentTypeID(c, "NN_WRAPPEDCOMPUTER")) { + nn_dropComponent(c); + return NULL; + } + if(nn_setComponentMethodsArray(c, methods, NN_COMPNUM_COUNT)) { + nn_dropComponent(c); + return NULL; + } + return c; +} + typedef enum nn_EENum { NN_EENUM_GETSIZE, NN_EENUM_GETDATASIZE, @@ -5600,6 +5663,9 @@ typedef enum nn_ModemNum { NN_MODEMNUM_SEND, NN_MODEMNUM_BROADCAST, + NN_MODEMNUM_GETWAKE, + NN_MODEMNUM_SETWAKE, + NN_MODEMNUM_COUNT, } nn_ModemNum; @@ -5610,6 +5676,7 @@ typedef struct nn_ModemState { } nn_ModemState; static nn_Exit nn_modemHandler(nn_ComponentRequest *req) { + if(req->action == NN_COMP_SIGNAL) return NN_OK; nn_Context *ctx = req->ctx; nn_ModemState *state = req->classState; nn_Computer *C = req->computer; @@ -5632,6 +5699,37 @@ static nn_Exit nn_modemHandler(nn_ComponentRequest *req) { mreq.state = req->state; mreq.modem = &state->modem; mreq.localAddress = req->compAddress; + nn_Exit e; + + if(req->action == NN_COMP_DROP) { + mreq.action = NN_MODEM_DROP; + state->handler(&mreq); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + + if(method == NN_MODEMNUM_ISWIRED) { + return nn_pushbool(C, isWired); + } + if(method == NN_MODEMNUM_ISWIRELESS) { + return nn_pushbool(C, isWireless); + } + if(method == NN_MODEMNUM_MAXPACKETSIZE) { + return nn_pushinteger(C, state->modem.maxPacketSize); + } + if(method == NN_MODEMNUM_MAXVALUES) { + return nn_pushinteger(C, state->modem.maxValues); + } + if(method == NN_MODEMNUM_GETSTRENGTH) { + mreq.action = NN_MODEM_GETSTRENGTH; + e = state->handler(&mreq); + if(e) return e; + req->returnCount = 1; + return nn_pushinteger(C, mreq.strength); + } + if(method == NN_MODEMNUM_MAXSTRENGTH) { + return nn_pushinteger(C, state->modem.maxRange); + } if(C) nn_setError(C, "modem: not implemented yet"); return NN_EBADCALL; @@ -5659,6 +5757,9 @@ nn_Component *nn_createModem(nn_Universe *universe, const char *address, const n [NN_MODEMNUM_SEND] = {"send", "function(targetAddress: string, port: integer, ...): boolean - Send a packet", NN_INDIRECT}, [NN_MODEMNUM_BROADCAST] = {"broadcast", "function(port: integer, ...): boolean - Broadcast a packet", NN_INDIRECT}, + + [NN_MODEMNUM_GETWAKE] = {"getWakeMessage", "function(): string?, boolean - Returns the wake message, if any, and whether it is fuzzy", NN_DIRECT}, + [NN_MODEMNUM_SETWAKE] = {"setWakeMessage", "function(message: string?, fuzzy: boolean) - Changes the wake-up message of the modem", NN_INDIRECT}, }; nn_Exit e = nn_setComponentMethodsArray( @@ -5679,3 +5780,36 @@ nn_Component *nn_createModem(nn_Universe *universe, const char *address, const n nn_setComponentHandler(c, nn_modemHandler); return c; } + +nn_Modem nn_defaultWiredModem = { + .maxRange = 0, + .maxValues = 8, + .maxPacketSize = 8192, + .maxOpenPorts = 16, + .isWired = true, + .basePacketCost = 50, + .fullPacketCost = 100, + .costPerStrength = 0, +}; +nn_Modem nn_defaultWirelessModems[2] = { + NN_INIT(nn_Modem) { + .maxRange = 16, + .maxValues = 8, + .maxPacketSize = 8192, + .maxOpenPorts = 16, + .isWired = true, + .basePacketCost = 100, + .fullPacketCost = 500, + .costPerStrength = 30, + }, + NN_INIT(nn_Modem) { + .maxRange = 400, + .maxValues = 8, + .maxPacketSize = 8192, + .maxOpenPorts = 16, + .isWired = true, + .basePacketCost = 200, + .fullPacketCost = 1000, + .costPerStrength = 20, + }, +}; diff --git a/src/neonucleus.h b/src/neonucleus.h index cde15db..25d9454 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -903,6 +903,14 @@ nn_Exit nn_popSignal(nn_Computer *computer, size_t *valueCount); // The high-level API of the built-in component classes. // These components still make no assumptions about the OS, and still require handlers to connect them to the outside work. +// Wrapping a computer as a component. +// It's a new instance each time. +// The computer MUST NOT be dropped before this component is fully gone. + +nn_Exit nn_transferErrorFrom(nn_Exit exit, nn_Computer *from, nn_Computer *to); +nn_Computer *nn_fromWrappedComputer(nn_Component *component); +nn_Component *nn_wrapComputer(nn_Computer *computer); + // EEPROM class // reads and writes are always 1/1 @@ -1586,10 +1594,6 @@ extern nn_Modem nn_defaultWirelessModems[2]; typedef enum nn_ModemAction { // modem dropped NN_MODEM_DROP, - // modem mounted to a computer, meant to bind - NN_MODEM_MOUNTED, - // modem unmounted to a computer, meant to unbind - NN_MODEM_UNMOUNTED, // check whether a port is open NN_MODEM_ISOPEN, // open a port @@ -1602,6 +1606,8 @@ typedef enum nn_ModemAction { NN_MODEM_SEND, // get current modem strength NN_MODEM_GETSTRENGTH, + // set current modem strength + NN_MODEM_SETSTRENGTH, // returns the wake message NN_MODEM_GETWAKEMESSAGE, // set the wake message