From 9b79fae0be021e81146c076739d58c3c14227db2 Mon Sep 17 00:00:00 2001 From: sejo Date: Tue, 12 Oct 2021 16:54:14 -0500 Subject: [PATCH] file device --- src/uxn_tutorial_day_7.gmo | 190 ++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 2 deletions(-) diff --git a/src/uxn_tutorial_day_7.gmo b/src/uxn_tutorial_day_7.gmo index d77174b..1ea4661 100644 --- a/src/uxn_tutorial_day_7.gmo +++ b/src/uxn_tutorial_day_7.gmo @@ -1,9 +1,195 @@ # uxn tutorial: day 7, more devices -(work in progress) +this is the seventh and last section of the <(uxn tutorial)>! here we talk about the devices in the varvara computer that we haven't covered yet: audio, file, and datetime. + +this should be a light and calm end of our journey, as it has to do less with programming logic and more with the input and output conventions in these devices. + +let's begin! + +# the file device + +the file device in the varvara computer allows us to read and write to external files. + +its ports are normally defined as follows: + +``` +|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ] +``` + +* the vector short is currently unused +* the success short stores the length of the data that was successfully read or written, or zero if there was an error +* offset-hs and offset-ls are a couple of shorts that compose a 32-bits number corresponding to an offset for the reading or writing of a file: how many bytes should the operation skip from the beginning of the file. +* the name short is for the memory address where the filename (null-terminated, i.e. with a 00) is stored +* the length short is the amount of bytes to read or write: don't forget that the program memory is ffff plus 1 bytes long, and that the program itself is stored there! +* the load short is for the starting memory address where the read data should be stored +* the save short is for the starting memory address where the data to be written is stored + +a read operation is started when the load short is written to, and a write operation is started when the save short is written to. + +these might seem like a lot of fields, but we'll see that they are not too much of a problem! + +## reading a file + +in order to read a file, we need to know the following: + +* the path of the file, written as a string of text in program memory: terminated by a 00, and with an appropriate label - this path would be relative to the location where uxnemu is ran. +* the amount of bytes that we want to read from the file: it's okay if this number is not equal to the size of the file; it can be smaller or even greater. +* the label for a reserved section of program memory where read data will be stored + +and that's it! + +we can use a structure like the following, where the filename and reserved memory are under a label, and the load-file subroutine under another one: + +``` +@load-file ( -- ) + ;file/name .File/name DEO2 ( set address of file path ) + #00ff .File/length DEO2 ( will attempt to read 255 bytes ) + ;file/data .File/load DEO2 ( set address for the data to read, and read ) + + ( check the success byte and jump accordingly ) + .File/success DEI2 #0000 EQU2 ,&failed JCN + + &success + LIT 'Y .Console/write DEO + RTN + + &failed + LIT 'N .Console/write DEO +RTN + +@file + &name "test.txt 00 + &data $ff ( reserving 255 bytes for the data ) +``` + +note that in this case we are writing a character to the console according to the success short being zero or not, but we could decide to take any action that we consider appropriate. + +also, in this example we are not really concerned with how many bytes were actually read: keep in mind that this information is stored in File/success until another read or write happens! + +it's important to remember that, as always in this context, we are dealing with raw bytes. + +not only we can choose to treat these bytes as text characters, but also we can choose to use them as sprites, coordinates, dimensions, colors, etc! + +## writing a file + +in order to write a file, we need: + +* the path of the file +* the amount of bytes that we want to write into the file +* the label for the section of program memory that we will write into the file + +keep in mind that the file will be completely overwritten unless you set some offset! + +the following program will write "hello" and a newline (0a) into a file called "test.txt": + +``` +@save-file ( -- ) + ;file/name .File/name DEO2 ( set file name ) + #0006 .File/length DEO2 ( will attempt to write 6 files ) + ;file/data .File/save DEO2 ( set data starting address, and write ) + .File/success DEI2 #0006 NEQ2 ,&failed JCN + + &success + LIT 'Y .Console/write DEO + RTN + + &failed + LIT 'N .Console/write DEO +RTN + +@file + &name "test.txt 00 + &data "hello 0a +``` + +note how similar it is to the load-file subroutine! + +the only differences, beside the use of File/save instead of File/load, are the file length and the comparison for the success short: in this case we know for sure how many bytes should have been written. + +## offsets + +if we wanted to read or write our file starting from a specific position (in bytes) in it, different from its beginning, we'd need to set the File/offset-ls short, and very rarely (i guess) the File/offset-hs short. + +for example, if we wanted to continue writing to our file after the "hello" and newline, we could set: + +``` +#0006 .File/offset-ls DEO2 +``` + +and then the next write will not overwrite the file, but append to it. + +## a brief case study: the theme file + +varvara programs written by 100r tend to have the ability to read a "theme" file that contains six bytes corresponding to the three shorts for the system colors. + +this file has the name ".theme" and can be written to a local directory from nasu, using the ctrl+p shortcut. + +=> https://wiki.xxiivv.com/site/theme.html uxn themes + +### reading the theme file + +we could adapt our previous subroutine in order to load the theme file and apply its data as system colors: + +``` +@load-theme ( -- ) + ;theme/name .File/name DEO2 ( set address of file path ) + #0006 .File/length DEO2 ( will attempt to read 6 bytes ) + ;theme/data .File/load DEO2 ( set address for the data to read, and read ) + + ( check the success byte and jump accordingly ) + .File/success DEI2 #0006 NEQ2 ,&failed JCN + + &success + ( set the system colors from the read data ) + ;theme/r LDA2 .System/r DEO2 + ;theme/g LDA2 .System/g DEO2 + ;theme/b LDA2 .System/b DEO2 + RTN + + &failed +RTN + +@theme + &name ".theme 00 + &data ( reserving 6 bytes for the data: ) + &r $2 &g $2 &b $2 +``` + +### writing the theme file + +and for doing the opposite operation, we can read the system colors into our reserved space in memory, and then write them into the file: + +``` +@save-theme ( -- ) + ( read system colors into program memory ) + .System/r DEO2 ;theme/r STA2 + .System/g DEO2 ;theme/g STA2 + .System/b DEO2 ;theme/b STA2 + + ;theme/name .File/name DEO2 ( set address of file path ) + #0006 .File/length DEO2 ( will attempt to write 6 bytes ) + ;theme/data .File/save DEO2 ( set address for the data and write ) + + ( check the success byte and jump accordingly ) + .File/success DEI2 #0006 NEQ2 ,&failed JCN + + &success + ( report success? ) + RTN + + &failed +RTN +``` + +i invite you to compare these subroutines with the ones present in the 100r programs like nasu! + +=> https://git.sr.ht/~rabbits/nasu/tree/main/item/src/main.tal nasu source code * the audio device * practice: small music instrument -* file device: saving and loading a simple state * datetime device: reading the date and time * practice: visualization of time + +# support + +if you found this tutorial to be helpful, consider sharing it and giving it your <(support)> :)