file device
This commit is contained in:
parent
68df772613
commit
9b79fae0be
|
@ -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)> :)
|
||||
|
|
Loading…
Reference in New Issue