Skip to content

Commit

Permalink
Merge pull request #2 from remy/http
Browse files Browse the repository at this point in the history
  • Loading branch information
remy authored Apr 6, 2021
2 parents 7b823f7 + ebe8202 commit 787b574
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 139 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ cspect_win.dat
cspect.log
httpbank.dot
httpbank.map
http.map
debug/
58 changes: 30 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,73 @@
# httpbank - for the Spectrum Next (public beta)
# http - for the Spectrum Next (public beta)

A utility for application developers to talk to web servers to exchange small blocks of data, such as high scores, game progress, etc.

This works best on small blocks of data. Requesting a 7K `.scr` does work, but has been seen as intermittent. Requesting 1K will work pretty much every time.
A utility for application developers to talk to web servers to exchange blocks of data, such as high scores, game progress. The `.http` dot command can also download and save to files over the web.

Usage:

```
; Send 1024 bytes from bank 22 to http://192.168.1.100:8080/send
.httpbank post -b 22 -l 1024 -h 192.168.1.100 -p 8080 -u /send
.http post -b 22 -l 1024 -h 192.168.1.100 -p 8080 -u /send
; Download and save Manic Miner http://zxdb.remysharp.com/get/18840
.http -h zxdb.remysharp.com -u /18840 -f manic.tap
; Load http://data.remysharp.com/1 into bank 26 and flash border red (2)
.httpbank get -b 26 -h data.remysharp.com -u /1 -f 2
; Load http://data.remysharp.com/1 directly into bank 26 and flash border red (2)
.http get -b 26 -h data.remysharp.com -u /1 -v 2
```

Options:

- `-b` bank number in 16K blocks
- `-f` filename (only available in `get` and cannot be used with `-b`)
- `-l` length of bytes to send
- `-o` address offset (defaults to 0)
- `-h` host address
- `-p` port number (defaults to 80)
- `-u` url (defaults to `/`)
- `-f` flash the border to n 0-7 (defaults to no flashing) and restores original border on exit
- `-v` flash the border to n 0-7 (defaults to no flashing) and restores original border on exit
- `-7` enabled base64 decoding (useful for supporting [Cspect](http://cspect.org/) and 7-bit binary exchange*)

Note that by default a GET request will empty out the bank selected. If you want to preserve the data in the bank, use a negative value for the offset, i.e. `-b 5 -o -0` will load the http request into bank 5, preserving the RAM and inserting at memory position 0 (in fact, `$4000` in RAM).

Run with no arguments to see the help.

*Cpsect's emulated ESP support used 7-bit, which means if you want to send binary data, you will need to base64 encode your payload. Using the `-7` flag with `httpbank` will support decoding and support Cpsect. This is not required if you only plan to exchange 7-bit data (like readable text) or support hardware. See the example folder for a server returning binary using base64 encoding.

**What this is not:** a web browser or a tool for downloading large files over the web (>16K - yes, that's "large"). Feel free to build on this source code if that's what you're looking for.
*Cpsect's emulated ESP support used 7-bit, which means if you want to send binary data, you will need to base64 encode your payload. Using the `-7` flag with `http` will support decoding and support Cpsect. This is not required if you only plan to exchange 7-bit data (like readable text) or support hardware. See the example folder for a server returning binary using base64 encoding.

## Using from NextBASIC

If the dot command isn't shipped as part of the distro and you want to ship `httpbank` as part of your project, you will need to call the dot command from a relative path. You might also need to set variables, such as a bank number through NextBASIC and pass this to `httpbank`. At time of writing (Feb 2021) the `.$` command doesn't support relative paths, so NextBASIC variable reading is support as part of `httpbank`.
If the dot command isn't (currently) shipped as part of the distro and you want to ship `http` as part of your project, you will need to call the dot command from a relative path. You might also need to set variables, such as a bank number through NextBASIC and pass this to `http`. At time of writing (Feb 2021) the `.$` command doesn't support relative paths, so NextBASIC variable reading is support as part of `http`.

The only variables that `httpbank` supports are single letter string variables.
The only variables that `http` supports are single letter string variables.

Assuming `httpbank` is in the same directory as your NextBASIC file, the following prefix is required: `../` (dot dots and a slash). See the code below for the full example:
Assuming `http` is in the same directory as your NextBASIC file, the following prefix is required: `../` (dot dots and a slash). See the code below for the full example:

```
10 BANK NEW b
20 b$ = STR$ b : REM store as a string
30 c$ = "256" : REM we'll send 256 bytes from bank $b
30 ../httpbank post -b b$ -h example.com -l c$
30 ../http post -b b$ -h example.com -l c$
40 PRINT "done"
```

Note that `httpbank` will expect a BASIC variable to represent a single argument value and you cannot combine multiple arguments into a single variable (i.e. `h$="-h example -p 8080` won't work).
Note that `http` will expect a BASIC variable to represent a single argument value and you cannot combine multiple arguments into a single variable (i.e. `h$="-h example -p 8080` won't work).

## Installation

You can save the `httpbank` to your own `/dot` directory, or you can run it from your working directory using a relative path `../httpbank`.
You can save the `http` to your own `/dot` directory, or you can run it from your working directory using a relative path `../http`.

**Download the latest [release here](https://github.com/remy/next-httpbank/releases)**
**Download the latest [release here](https://github.com/remy/next-http/releases)**

## Example servers

I've written a number of [example servers](https://github.com/remy/next-httpbank/tree/main/example/servers) in different languages for you to try out.
I've written a number of [example servers](https://github.com/remy/next-http/tree/main/example/servers) in different languages for you to try out.

## Limits

- When using a domain name, I've found that `CNAME` records can result in `DNS Error` so make sure to use `A` records ideally - you'll see error `2`.
- There's no SSL/TLS support - ensure your host is on *plain* http.
- Large binary `get` on Cpsect intermittently to fail (or my ESP is returning the data oddly)
- CSpect's ESP "emulation" doesn't have an 8-bit mode, so if you're sending or receiving bytes that are in the 8-bit range, i.e. above `$7F` the emulation won't work. If you want want to support cspect, then you can use the `-7` flag and your server will need to use base64 encoding. If your data is 7-bit (i.e. you have no byte values larger than `$7F`) then Cspect should work without extra options.
- Zesarux requires ESP bridging - I've not been able to test this, if you have feedback, please let me know.
- I've noticed when using Cspect's emulation, if the host can't be reached, Cspect will hang entirely.
- I've noticed when using Cspect's emulation, if the host can't be reached, Cspect will hang indefinitely.
- When using the `offset` you are constrained to 16K, so if the offset is 8,192, then the max length is also 8,192 (there's no error checking on this currently)

## Not supported / future
Expand All @@ -78,23 +77,23 @@ I've written a number of [example servers](https://github.com/remy/next-httpbank

## Debugging and problems

This repo also includes a debug build of `httpbank`. The difference is that it will add all the ESP read and write to the second half of the bank you use. This way you can debug from the real hardware and capture exactly what's going on.
This repo also includes a debug build of `http`. The difference is that it will add all the ESP read and write to the second half of the bank you use. This way you can debug from the real hardware and capture exactly what's going on.

**Important** the debug dot command uses the second half of the bank you use, so ideally test with less than 8K to help debugging.

If you need to file an issue, this information is extremely valuable for debugging - and if you're not comfortable including the file in [an issue](https://github.com/remy/next-httpbank/issues/new) as an attachment, you can email me directly at [email protected]. To capture this, run:
If you need to file an issue, this information is extremely valuable for debugging - and if you're not comfortable including the file in [an issue](https://github.com/remy/next-http/issues/new) as an attachment, you can email me directly at [email protected]. To capture this, run:

```
10 ../httpbank-debug.dot -h example.com -u / -b 20
20 SAVE "httpbank-debug.bin" BANK 20
10 ../http-debug.dot -h example.com -u / -b 20
20 SAVE "http-debug.bin" BANK 20
```

Then include the `httpbank-debug.bin` that was saved on your Next to help debug the issue.
Then include the `http-debug.bin` that was saved on your Next to help debug the issue.

### Notes on httpbank-debug.dot
### Notes on http-debug.dot

1. Does not erase the bank
2. The contents of the `State` structure (in `state.asm`) are written to the 2nd half of the bank, i.e. the second 8K MMU
2. The contents of the `State` structure (in `state.asm`) are written to the 2nd half of the bank, i.e. the second 8K page
3. After the `State` object, around 519 bytes later, the ESP exchange are stored, including the AT commands and ESP raw response.
4. `Wifi.getPacket` writes to the end of the bank with the `IX` register state as a stack like array - this is to debug the final parsing of the base64 encoded packet

Expand All @@ -117,6 +116,8 @@ Then include the `httpbank-debug.bin` that was saved on your Next to help debug
- `F` Port error - must be a number
- `G` Border option error - must be a number between 0 and 7
- `H` Hostname is required
- `I` Filename or bank must be specified (command is missing the `-b` or `-f` argument)
- `J` Could not open file for writing

## Development

Expand All @@ -129,6 +130,7 @@ Then include the `httpbank-debug.bin` that was saved on your Next to help debug
- [Alexander Sharikhin](https://github.com/nihirash) - via internet-nextplorer (which uart.asm and much of wifi.asm is based)
- [Robin Verhagen-Guest](https://github.com/Threetwosevensixseven/NXtel) - via nxtp and nxtel source code
- [Peter Ped Helcmanovsky](https://github.com/ped7g/) - via dot commands and answering endless questions on discord
- [David Saphier](https://github.com/em00k/) - for starting and inspiring full "save to file" support

## License

Expand Down
Binary file added example/verify.bas
Binary file not shown.
24 changes: 24 additions & 0 deletions example/verify.bas.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#program verify
10 LAYER 0: CLS
20 BANK 20 ERASE
30 PRINT AT 0,0; INVERSE 1;"HTTP test suite"; INVERSE 0
40 ON ERROR GO SUB 9000
45 t$="4k":u$="/10":%r=2: GO SUB 1060
50 t$="8k":u$="/8":%r=4: GO SUB 1060
60 t$="16k":u$="/9":%r=6: GO SUB 1060
70 t$="32k":u$="/7":%r=8: GO SUB 1060
80 ON ERROR
90 PRINT FLASH 1;"Success"
1000 PAUSE 0: STOP
1060 PRINT AT %r,0;t$+" test..."
1070 t$=t$+".bin"
1080 .http -h data.remysharp.com -u u$ -f t$ -v 6
1090 PRINT AT %r,11;"done. Verifying: "
1100 c$=t$+" -1 -mb 20"
1110 .$ extract c$
1120 %i=% BANK 20 PEEK 0
1130 IF %i=$FF THEN PRINT AT %r,27; INVERSE 1;"OK"; INVERSE 0: ELSE PRINT AT %r,27; FLASH 1;"BAD": PAUSE 0: STOP
1140 RETURN

9000 ON ERROR
9050 PRINT FLASH 1;"ERROR": ERROR : PAUSE 0: STOP
Binary file added http
Binary file not shown.
Binary file added http-debug.dot
Binary file not shown.
Binary file removed httpbank
Binary file not shown.
Binary file removed httpbank-debug.dot
Binary file not shown.
115 changes: 100 additions & 15 deletions src/bank.asm
Original file line number Diff line number Diff line change
@@ -1,43 +1,63 @@
MODULE Bank

prevBankA DEFB 0
prevBankB DEFB 0
userBank DEFB 0
prevPageA DEFB 0
prevPageB DEFB 0
userBank DEFB 0,0

pageA EQU MMU4_8000_NR_54
pageB EQU MMU5_A000_NR_55

; NOTE: MMU3/5 are safe from being
; paged out when making NextZXOS
; calls (unlike MMU0/1/6/7)
;; NOTE: MMU3/5 are safe from being paged out when making
;; NextZXOS calls (unlike MMU0/1/6/7)

buffer EQU $8000
IFDEF TESTING
debug DW $A000
ENDIF

; A <- 16K bank number to use as active bank
; C <- 16K bank number to use as active bank
; Modifies: A, BC (via macro)
init:
;; double the value as we'll get 16K bank
add a, a
ld (userBank), a
push bc

;; backup the banks that are sitting over $8000 and $A000
;; note that with a dot file, the stack originally is sitting at $FF42
;; so if I do use this area, I need to set my own stackTop
NextRegRead pageA ; loads A with pageA bank number
ld (prevBankA), a
ld (prevPageA), a
NextRegRead pageB
ld (prevBankB), a
ld (prevPageB), a

pop bc

;; check the bank init method, `loadToBank` = 1 if we're loading
;; data in and out of banks, and set to 1 if we're working with
;; files
ld a, (State.fileMode)
and a
jr nz, .initNewBank

;; double the value as we'll get 16K bank
ld a, c
add a, a
ld (userBank), a

;; now page in our user banks
ld a, (userBank)
nextreg pageA, a ; set bank to A
inc a
nextreg pageB, a ; set bank to A
ret

.initNewBank
call allocPage
ld (userBank), a
nextreg pageA, a ; set bank to A

call allocPage
ld (userBank+1), a
nextreg pageB, a ; set bank to A

ret
erase:
ld bc, $4000 ; 16k
ld hl, buffer
Expand All @@ -48,13 +68,78 @@ erase:

restore:
push af ; protect the F flags
ld a, (prevBankA)

ld a, (prevPageA)
nextreg pageA, a
ld a, (prevBankB)
ld a, (prevPageB)
nextreg pageB, a

;; if fileMode = 0 we're done, otherwise release the pages
ld a, (State.fileMode)
and a
jr z, .done

;; if writing to a file, we need to release the 2 pages we allocated
ld a, (userBank)
ld e, a
call freePage

ld a, (userBank+1)
ld e, a
call freePage

.done
pop af
ret


;; via Matt Davies — 30/03/2021
allocPage:
push ix
push bc
push de
push hl

; Allocate a page by using the OS function IDE_BANK.
ld hl,$0001 ; Select allocate function and allocate from normal memory.
call .callP3dos
ccf
ld a,e
pop hl
pop de
pop bc
pop ix
ret nc
xor a ; Out of memory, page # is 0 (i.e. error), CF = 1
scf
ret

.callP3dos:
exx ; Function parameters are switched to alternative registers.
ld de,IDE_BANK ; Choose the function.
ld c,7 ; We want RAM 7 swapped in when we run this function (so that the OS can run).
rst 8
db M_P3DOS ; Call the function, new page # is in E
ret

freePage:
push af
push ix
push bc
push de
push hl

ld e,a ; E = page #
ld hl,$0003 ; Deallocate function from normal memory
call allocPage.callP3dos

pop hl
pop de
pop bc
pop ix
pop af
ret

ENDMODULE


Expand Down
4 changes: 2 additions & 2 deletions src/base64.asm
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ EncodedLength
rl l
rl h ; make sure to carry to H

or a ; now clear the carry
and a ; now clear the carry
rl l ; and repeat
rl h

Expand All @@ -85,7 +85,7 @@ EncodedLength
;; HL now contains estimated source length, now we substract
;; the original length stored in BC to work out how many
;; padding bytes we need
or a ; first clear the carry
and a ; first clear the carry
sbc hl, bc ; HL - BC (and the carry, but that's cleared)
ld a, l ; will be 0, 1 or 2
ld (State.paddingReal), a ; squirrel away for later
Expand Down
9 changes: 8 additions & 1 deletion src/border.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Border:
jr nc, .addColour
.userColour EQU $+1
ld a, SMC
or a ; reset carry
and a ; reset carry
jr .apply
.addColour
.newColour EQU $+1
Expand All @@ -28,3 +28,10 @@ Border:
and a, %00000111 ; mask the rest
ld (Border.userColour), a
ret

.Restore
ex af, af'
ld a, (Border.userColour)
out (254), a
ex af, af'
ret
Loading

0 comments on commit 787b574

Please sign in to comment.