A manual for the FujiNet network statements added to SmartBASIC 1.x R21
(built from the Rev-20 source) for the Coleco Adam. These commands let BASIC programs talk directly to a
FujiNet peripheral — fetching web pages, calling JSON
APIs, browsing TNFS file servers, and loading/saving programs over the network —
without any PRINT CHR$(4) plumbing.
New to the internals or building the binary? See FUJINET.md for the implementation, hook points, and build notes. Runnable examples are in NFUJI.BAS.
- Quick start
- Concepts
- Command reference
- Recipes
- Errors and troubleshooting
- Limitations
- Quick reference
- Installation
Fetch a web page and print it to the screen:
10 NOPEN 1,"N:HTTP://WWW.GNU.ORG/LICENSES/GPL-3.0.TXT",4,0
20 NSTATUS 1,BW,CONN,ERR
30 IF BW=0 AND CONN=0 THEN 80
40 IF BW=0 THEN 20
50 L=BW : IF L>255 THEN L=255
60 NREAD 1,A$,L : PRINT A$;
70 GOTO 20
80 NCLOSE 1That is the whole pattern: open a channel, poll status for bytes waiting, read them, and close when the host disconnects.
The connection commands (NOPEN, NCLOSE, NSTATUS, NREAD, NWRITE,
NJSONPARSE, NJSONQUERY) take a device number (a "channel") as their
first argument. The number 1..15 selects an EOS character device:
| First argument | EOS device | Common name |
|---|---|---|
1 |
9 | N1: |
2 |
10 | N2: |
| … | … | … |
15 |
23 | N15: |
In short, device = argument + 8. Channels 1 and 2 are the ones most
firmware builds expose; treat each channel as one independent connection. Passing
0 or a value above 15 raises an Illegal Quantity error.
The filesystem and program commands (NCD, NDIR, NMKDIR, NRMDIR,
NDEL, NLOAD, NSAVE) take no device number — they are one-shot
operations that always use channel 1 (N1:, EOS device 9). Because the
firmware runs them through that device, they displace whatever connection was
open on channel 1; use channel 2+ for connections you want to keep across
filesystem operations.
Where a command takes a path or URL, it is a FujiNet devicespec string that
begins with the network prefix N: and a protocol:
N:PROTO://[HOST][:PORT]/PATH...
Examples:
N:HTTP://WWW.GNU.ORG/LICENSES/GPL-3.0.TXT
N:HTTPS://API.EXAMPLE.COM/V1/STATUS
N:TCP://192.168.1.5:9000/
N:TNFS://TMA-3/GAMES/
Supported protocols depend on your FujiNet firmware, but typically include
HTTP, HTTPS, TCP, UDP, TNFS, FTP, and SSH. A trailing / usually
denotes a directory.
NOPEN's third argument selects how the connection is opened:
| Mode | Meaning |
|---|---|
4 |
Read (e.g. HTTP GET) |
8 |
Write (e.g. HTTP PUT) |
12 |
Read/write |
13 |
POST |
NOPEN's fourth argument controls end-of-line translation between the host and
the Adam:
| Trans | Meaning |
|---|---|
0 |
None (raw bytes) |
1 |
CR |
2 |
LF |
3 |
CR/LF |
4 |
PETSCII |
Use 0 for binary data; use 1 or 3 for text you intend to PRINT.
FujiNet streams data asynchronously, so you don't read a fixed length — you ask
how much is waiting and read that. NSTATUS returns three values:
- bytes waiting — how many bytes are ready to read right now;
- connected —
1while the resource is still open,0at end of stream; - error — the device's own status/error code (
1is the FujiNet "OK").
The canonical loop is: poll NSTATUS; if bytes are waiting, NREAD them; stop
when connected is 0 and nothing is waiting. See Quick start.
SmartBASIC strings hold at most 255 bytes, so NREAD, NWRITE, and
NJSONQUERY move at most 255 bytes per call. For larger transfers, loop (read a
chunk, process it, read again).
Notation: d is a device number (1..15); $ suffixes mark string
variables/expressions; other arguments are numeric.
Open a connection on channel d to the resource named by url$, using the given
open mode and translation mode.
NOPEN 1,"N:HTTP://WWW.GNU.ORG/LICENSES/GPL-3.0.TXT",4,0Opening a new resource on a channel replaces whatever was open there.
Close the connection on channel d. Always close channels you open.
NCLOSE 1Query channel d and store three results into the numeric variables you name:
bw— bytes waiting (0–65535);conn— connected flag (1= still open,0= finished);err— device error/status code.
NSTATUS 1,BW,CONN,ERR
IF ERR>1 THEN PRINT "DEVICE ERROR ";ERRIf
bwcan exceed 32767, store it in an integer variable (e.g.BW%); a plain floating-point variable would show large values as negative.
Read up to len bytes (max 255) from channel d into the string variable
buf$. buf$ is set to exactly the bytes actually read, which may be fewer than
len.
L=BW : IF L>255 THEN L=255
NREAD 1,A$,L
PRINT A$;Write len bytes from buf$ to channel d. If len is larger than the length
of buf$, only LEN(buf$) bytes are sent.
P$="HELLO FUJINET"
NWRITE 1,P$,LEN(P$)Tell channel d to parse the response body it has received as JSON. Call this
once after the data has arrived, before issuing queries.
NJSONPARSE 1
NJSONPARSEalso switches the channel into the firmware's JSON mode (a requirement for reading query results). After it,NREADon that channel returns JSON query values rather than the raw body; issue a freshNOPENif you want raw reads again.
Run the JSONPath/pointer query$ against the parsed JSON on channel d and put
the result text into the string variable a$ (up to 255 bytes).
NJSONQUERY 1,"/0/content",C$
PRINT C$These operate on the file server addressed by the devicespec (e.g. a TNFS host). They take no device number — each is a one-shot operation on channel 1 (see Channels and device numbers).
Set the current N: directory (prefix).
NCD "N:TNFS://TMA-3/GAMES"Open the directory named by path$ and print its listing to the screen,
then close it. Self-contained — no read loop needed.
NDIR "N:TNFS://TMA-3"Create the directory named by path$.
NMKDIR "N:TNFS://TMA-3/NEWDIR"Remove the directory named by path$ (it must be empty).
NRMDIR "N:TNFS://TMA-3/OLDDIR"Delete the file named by path$.
NDEL "N:TNFS://TMA-3/OLDFILE"These transfer a BASIC program as an ASCII listing (the same text you'd see
from LIST), so they interoperate with other tools and editors. Like the
filesystem commands they take no device number and always use channel 1.
Experimental. Use
NLOAD/NSAVEfrom immediate mode (likeLOAD/SAVE), not from inside a running program —NLOADrewrites program memory as it reads. Validate these two on real hardware before relying on them.
Write the current program to path$ as an ASCII listing.
NSAVE "N:TNFS://TMA-3/MYPROG.BAS"Read an ASCII program listing from path$ and enter it line by line (numbered
lines are added to the program; blank lines are ignored).
NLOAD "N:TNFS://TMA-3/MYPROG.BAS"10 NOPEN 1,"N:HTTP://WWW.GNU.ORG/LICENSES/GPL-3.0.TXT",4,0
20 NSTATUS 1,BW,CONN,ERR
30 IF BW=0 AND CONN=0 THEN 80
40 IF BW=0 THEN 20
50 L=BW : IF L>255 THEN L=255
60 NREAD 1,A$,L : PRINT A$;
70 GOTO 20
80 NCLOSE 110 NOPEN 1,"N:HTTPS://FUJINET.ONLINE/FUJINET.JSON",4,0
20 NJSONPARSE 1
30 NJSONQUERY 1,"/0/content",C$
40 PRINT C$
50 NCLOSE 110 NOPEN 1,"N:TCP://192.168.1.5:9000/",12,0
20 M$="HELLO FUJINET" : NWRITE 1,M$,LEN(M$)
30 NSTATUS 1,BW,CONN,ERR
40 IF BW=0 THEN 30
50 L=BW : IF L>255 THEN L=255
60 NREAD 1,R$,L : PRINT R$;
70 NCLOSE 110 NCD "N:TNFS://TMA-3"
20 NDIR "N:TNFS://TMA-3"
30 NMKDIR "N:TNFS://TMA-3/NEWDIR"
40 NDEL "N:TNFS://TMA-3/OLDFILE"
50 NRMDIR "N:TNFS://TMA-3/NEWDIR"] NSAVE "N:TNFS://TMA-3/MYPROG.BAS"
] NEW
] NLOAD "N:TNFS://TMA-3/MYPROG.BAS"
] RUN
Argument errors are reported as ordinary BASIC errors:
| Error | Cause |
|---|---|
Illegal Quantity |
Device number outside 1..15, a numeric argument outside 0..255, or the selected network device is not present on AdamNet (e.g. no FujiNet attached) |
Type Mismatch |
A string was given where a number was expected (or vice versa), e.g. a non-string in a url$/buf$ slot |
Network and device errors are not raised as BASIC errors. A failed open,
read, or write does not stop your program — instead, the condition shows up in
NSTATUS's err value (and a read simply returns no bytes). Always check
NSTATUS when something doesn't behave:
NSTATUS 1,BW,CONN,ERR
PRINT "WAITING=";BW;" CONNECTED=";CONN;" ERR=";ERRerr = 1 is the FujiNet "OK" status. Other common values include end-of-file and
protocol-specific codes; consult your firmware's documentation.
Nothing happens / hangs: make sure the FujiNet is powered and on AdamNet,
that the channel number matches an available network device (usually 1 or 2),
and that your devicespec begins with N: and a supported protocol.
- 255 bytes per transfer for
NREAD/NWRITE/NJSONQUERY(loop for more). Larger bursts from the device are buffered internally (up to 1024 bytes per packet) and served to successiveNREADs, so nothing is lost. NREADblocks until the device has something to send — pollNSTATUSand only read when bytes-waiting is nonzero.NSTATUSbytes-waiting above 32767 should use an integer (%) variable.NDIRopens the path as a directory (open mode 6, the firmware'sDIRECTORYaccess mode) and drains it to the screen before closing.NLOAD/NSAVEare experimental (they reuse the interpreter'sLISTand line-entry paths) and are intended for immediate mode.NLOADaccepts CR, LF, or CR/LF line endings.- The command bytes (including
,*+!for the filesystem ops and0xFCfor JSON channel mode) are confirmed against the current FujiNet firmware'slib/device/adamnet/network.cpp.
Commands
| Command | Form | Summary |
|---|---|---|
NOPEN |
d, url$, mode, trans |
Open a connection |
NCLOSE |
d |
Close a connection |
NSTATUS |
d, bw, conn, err |
Bytes waiting / connected / error |
NREAD |
d, buf$, len |
Read ≤ len bytes into buf$ |
NWRITE |
d, buf$, len |
Write min(len, LEN(buf$)) bytes |
NJSONPARSE |
d |
Parse the response as JSON |
NJSONQUERY |
d, query$, a$ |
JSONPath query → a$ |
NCD |
path$ |
Set the N: directory (channel 1) |
NDIR |
path$ |
Print a directory listing (channel 1) |
NMKDIR |
path$ |
Make a directory (channel 1) |
NRMDIR |
path$ |
Remove an empty directory (channel 1) |
NDEL |
path$ |
Delete a file (channel 1) |
NLOAD |
path$ |
Load an ASCII program listing (channel 1) |
NSAVE |
path$ |
Save the program as ASCII (channel 1) |
Open modes: 4 read · 8 write · 12 read/write · 13 POST
Translation: 0 none · 1 CR · 2 LF · 3 CR/LF · 4 PETSCII
Device: channel argument n → EOS device n + 8 (1→9, 2→10, …);
the no-argument commands always use channel 1 (device 9)
The commands are built into the SmartBASIC 1.x binary assembled from
SmartBASIC 1.x Rev-20_SB1X20Y.ASM. Run make to assemble it with z88dk's
z80asm and package it into a bootable EOS DDP image
(SmartBASIC 1.x Rev-20_SB1X20Y.ddp) — boot that in an emulator or write it
to media for real hardware. See FUJINET.md for build details,
the three hook points, and the validation procedure.
FujiNet commands © 2026. SmartBASIC 1.x © 1991, 1997 Richard F. Drushel, released for the ADAM community. Built on the FujiNet fujinet-lib protocol and the EOS C bindings. GPL v3, see the source headers.