11 KiB
Vanilla components needed
Not everything OC has (as a few of them are really MC-centered) but most of it.
computercomponentinternetcomponent (note: NN does not handle internet requests, those are up to the emulator)relaycomponent (note: OCDoc still refers to it asaccess_point)geolyzercomponentredstonecomponentmotion_sensorcomponentprinter3dcomponent (note: maybe add signal for when printer completes?)signcomponentmicrocontrollercomponenthologramcomponentdisk_drivecomponentnote_blockcomponent
Custom components needed
oledcomponent (OLED screen, a store of draw commands and resolution from NN's perspective)ipucomponent, an Image Processing Unit. Can bind witholeds, and issues said draw commandsvt, a combination of a GPU, a screen and a keyboard with limited functionality. Offers direct operations on the video memory- (maybe)
qpucomponent, a Quantum Processing Unit for quantum computing radio_controllerandradio_towercomponents, for radio telecommunications- (maybe)
clockcomponent for arbitrary precision time-keeping ledcomponent for LED matrixes and/or LED lightsspeakercomponent, allows playing audio by asking for binary samples and pushing a signal when it needs moremicrophonecomponent, allows reading audio from nearby sourcestape_drivecomponent, compatible with Computronicscd_driveto work with CDs (can be read-only, write-only or read-write)serialcomponent, for serial communications with other devices (see Serial)iron_noteblockcomponentcolorful_lampcomponent
To make it good
- make more stuff const if it can be. Gotta help out the optimizer
- put a bunch of internal-only functions as fastcall
- write a bunch of unit tests to ensure the public API works correctly
- ensure OOMs are recoverable
- do a hude audit for bugs at some point
To make it fast
NOTE: we're mostly bottlenecked by the architecture (typically a Lua VM) and the intentional bottlenecking from call costs. breaking changes are allowed but like try to avoid them.
- make signals use a circular buffer instead of a simple array
- use more arenas if possible
- reduce pointer nesting, not only for simplicity, but so we spend less time reading from main memory
Component extensions
filesystem
getMaxRead(): integer, returns the maximum size of a read; effectively the ideal buffer size
drive
readUByte(byte: integer): integer, reads an unsigned byte
Unique components
Subject to change, still being discussed with the other NeoFlock members.
Serial
The serial component would have the methods:
read(len: integer): string, to read datawrite(data: string): boolean, to send dataisConnected(): boolean, to check if the port is currently connectedsetProtocol(protocol: string): string, sets the protocol string of our port, which may be truncated.getProtocol(): string, gets the currently registered protocol of our port. Default israw.
It would also push the following signals:
serial_connected(portAddress: string, protocol: string), when connectedserial_protocol(portAddress: string, protocol: string), when other side changed protocol mid-connection.serial_disconnected(portAddress: string), when the port is disconnectedserial_data(portAddress: string, amount: integer), when new data is available (and how much)
Radio
For very large-distance telecommunications. Frequency is in Hz.
The radio_controller component, which enables listening to connected radio towers
isOpen(): boolean, whether listening is enabledopen(): boolean, to open for listeningclose(): boolean, to close the listenersetRange(minimum: number, maximum: number): boolean, sets the frequency range we listen for.getRange(): number, number, gets the frequency range we listen for.
The radio_tower component, which actually receives and sends the waves
isEmitter(): boolean, whether this tower can, in fact, send radio wavesminFrequency: number, the minimum frequency it can detect and transmit (getter field)maxFrequency: number, the maximum frequency it can detect and transmit (getter field)resolution: integer, how many frequencies can be listened for in that range. The frequencies sent to the controller are rounded to one of these (getter field)getRangeOf(frequency: number): number, to get the maximum range for a given frequencymaxPacketSize(): integer, to get the maximum size that can be sent at once, typically 32KiB.baseFrequency: number, gets the base frequency of radio communications, typically 100 kHz. (getter field)emit(frequency: number, data: string): boolean, to emit a radio packet on a given frequency. The frequency must be in range, and will be rounded to one within resolution
Radio waves travel at a (likely configurable) speed and have extremely large range on lower frequencies. They can also have bit flips.
The range and speed are based off the frequency range. Given base frequency f0, base energy cost e0, base range r0, we can compute energy cost e, range r of a given frequency f using:
r = r0 / (f / f0)e = e0 * (f / f0)
When one is received, it will push:
radio_message(localControllerAddress: string, localTowerAddress: string, distance: number, frequency: number, data: string), where frequency is rounded to within the resolution of the tower. It does ensure the frequency is within the controller range and the controller is open. Data may be corrupted by bit flips. Distance is in meters. As you can notice, there is no sender address. It is the responsibility of the protocol to identify and verify senders.
VT
A generic virtual terminal. Like a GPU + screen, but with no VRAM. Has a 256-color palette representing ANSI 256 colors. Subsequently, colors 0-15 represent ANSI escape colors. The entire palette is editable.
The vt component has:
getResolution(): integer, integer, to get the resolution. Cannot be changedgetDepth(): integer, to get the color depth. Cannot be changedgetColor(index: integer): integer, to get a colorsetColor(index: integer, color: integer): integer, sets a color and returns the old one. Characters who's colors were table indexes would be updatedsetForeground(color: integer, fromTable?: boolean), sets a foreground color, optionally as a table indexgetForeground(): integer, integer?, returns what the foreground color was, and the table index if applicablesetBackground(color: integer, fromTable?: boolean), sets a background color, optionally as a table indexgetBackground(): integer, integer?, returns what the background color was, and the table index if applicableset(idx: integer, data: string): boolean, to write to the screen's unicode buffer. Whiledatais UTF-8, the buffer stores codepoints. Pretend the terminal does an internal conversion from UTF-8 to UTF-32getColorOf(idx: integer): integer, integer, integer?, integer?, to get the foreground color, background color, and palette indexes of a tileget(idx: integer, len: integer): string, to get the contents of part of the VT's unicode buffer, encoded as UTF-8
It also pushes the signals of keyboards and screens (no precise) for using input.
The unicode buffer is a 0-indexed buffer of codepoints alongside the color data. When writing to the unicode buffer, it also writes to the color buffer.
If x and y are 0-indexed, then x + y * width is the index in the buffer
CD drives
The cd_drive component has:
hasDisk(): boolean, to check whether a disk is in the driveisReadonly(): boolean, to check whether the drive is read-only (often is)isDiskErasable(): boolean, to check whether the disk is erasable, which requires support from both the disk and the drivegetCapacity(): integer, gets the capacity of the disktell(): integer, current 0-indexed byte offset into the diskseekTo(position: integer): boolean, seek to a 0-indexed byte offset in the diskmoveBy(delta: integer): boolean, move the current position by some amount of bytes (+/-), can wrap aroundmaxReadSize(): integer, to return the maximum size of a readread(len: integer): string, to read some data. Does wrap aroundwrite(data: string): boolean, to write some data. Does wrap around.
It also pushes the signals:
cd_added(driveAddress: string), for when a disk is addedcd_removed(driveAddress: string), for when a disk is removed
Writing to non-erasable drives
Instead of erroring out, it instead ORs the bits between what was there and what is written. This means you can still write the initial contents, as the CD starts out 0'd, but subsequent writes are likely to corrupt previous ones.
CDs vs tape
Tape is slow. CDs are fast. Tape is always fully writable. CDs may not always be erasable. Tape has high capacity, CDs do not.
CDs vs unmanaged floppies
CDs require special software support, while floppies appear as just smaller HDDs. Unmanaged floppies are always erasable, while CDs may not be. CDs are typically lower capacity.
LED
The led_matrix component has:
getResolution(): integer, integer, gets the resolution of the LED matrix.getIntensity(x: integer, y: integer): number, gets the intensity of an LED.setIntensity(x: integer, y: integer, intensity: number): number, sets the intensity of an LED and returns the old one.
Intensity is between 0 (off) and 1 (full brightness). An LED matrix has really high call budget, thus it is ideal for frequency updating status updates.
nandflash
Heavily inspired by ossm_flash
getWearLevel(): number, returns a number from 0 to 100, where 0 means full life and 100 means deadgetSectorSize(): integer, returns the logical sector sizegetCapacity(): integer, the capacity, in bytes, of the flash storagegetLayers(): integer, returns the layering amount, for example 3 for TLC. Effectively an indication for lifetime, with higher being worse.readSector(sec: integer): string, read a sectorwriteSector(sec: integer, data: string): boolean, write a sectorreadByte(byte: integer): integer, reads a signed bytereadUByte(byte: integer): integer, reads an unsigned bytewriteByte(byte: integer, val: integer): boolean, writes a byteisReadonly(): boolean, check whether flash is read-onlygetLabel(): string?, get drive labelsetLabel(label: string?): string?, get drive label
Speaker
TODO: interface
Microphone
TODO: interface
OLED/IPU
TODO: interface
To re-evaluate
- Make the hashmap growing/shrinking to save on memory.
- Exposing the internal hashmap implementation.
- Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them to be made more portable.
- Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.