Compare with Previous | Blame | View Log
;The MIT License
;
;Copyright (c) 2010 Dylan Smith
;
;Permission is hereby granted, free of charge, to any person obtaining a copy
;of this software and associated documentation files (the "Software"), to deal
;in the Software without restriction, including without limitation the rights
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;copies of the Software, and to permit persons to whom the Software is
;furnished to do so, subject to the following conditions:
;
;The above copyright notice and this permission notice shall be included in
;all copies or substantial portions of the Software.
;
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;THE SOFTWARE.
; Control channel for BASIC streams.
; The control channel allows the BASIC programmer to find out the state
; of a stream and do things to the stream.
; The control streams have different metadata than a normal file or
; socket. There should be only one control stream so it has only one
; (very short) buffer in a fixed location. Therefore the stream
; information block that normally holds things like buffer offsets instead
; has:
; byte 0: flags
; byte 1: current command
; byte 2: state of current cmd
; byte 3: stream to act upon
.include "zxrom.inc"
.include "zxsysvars.inc"
.include "spectranet.inc"
.include "defs.inc"
.text
;-------------------------------------------------------------------------
; Control stream entry point
.globl F_control
F_control:
bit 7, l
jr nz, F_read_ctrlstream
; F_write_ctrlstream
; Sets the function of the control stream. This allows the BASIC
; programmer do something like "INPUT#4;"command";a%".
; Enter with L=stream
.globl F_write_ctrlstream
F_write_ctrlstream:
ex af, af'
call F_findmetadata ; find our metadata table
ex af, af'
cp 0x21 ; check it's not a control char of some sort
jp c, F_leave ; if so ignore it
ld (ix+OFS_CURCMD), a ; store the putative command
ld (ix+OFS_CURSTATE), 0 ; clear the current state
jp F_leave
;-------------------------------------------------------------------------
; F_read_ctrlstream
.globl F_read_ctrlstream
F_read_ctrlstream:
call F_findmetadata ; stream metadata now pointed to by IX
ld hl, ZX_TV_FLAG ; the mode is considered unchanged
res 3, (hl)
.isinkey3: ; The control stream only works with
ld hl, (ZX_ERR_SP) ; INPUT#, make INKEY$ a no-op
ld e, (hl)
inc hl
ld d, (hl)
and a
ld hl, 0x107F ; Compare with ED_ERROR
sbc hl, de
jp nz, .wasinkey3
ld a, (ix+OFS_CURCMD) ; find out the command in use
cp CMD_POLLALL
jp z, J_pollall
and a
jr z, .nocmd3
.badcmd3:
ld hl, STR_badcmd ; Unknown command
jp F_sendbuf
.nocmd3:
ld hl, STR_nocmd
jp F_sendbuf
.wasinkey3:
xor a ; Z and C reset - no data
ld l, 1 ; Don't fix the stack
jp F_leave
;-------------------------------------------------------------------------
; J_pollall
; Find out which stream (if any) has data waiting for it.
; Note that not all sockets may be being used by BASIC, some may be used
; by ROM modules or other machine code programs. If a socket that's
; ready is not for a BASIC stream it gets ignored.
J_pollall:
ld a, (ix+OFS_CURSTATE) ; check current state
and a ; if is zero, do the actual poll
jr nz, .retsockstate3 ; return the socket state
ld (ix+OFS_CURSTATE), 1 ; set current state flag to "get status"
; Check to find out whether there is pending data already
; in the buffer.
.checkbufs3:
; start with HL pointing at the first potential FD
ld hl, BUFMETADATA+STRM_FLAGS+BUFDATASZ
ld b, 15 ; maximum number of iterations
ld c, a ; store fd
.findloop_buf3:
xor a ; check flags for the stream
cp (hl) ; - for a socket, should all be zero
jr nz, .nextbuf3
dec l ; point at the read buffer current
dec l ; pointer
cp (hl)
jr nz, .bufrdy3 ; a buffer still has stuff in it
inc l
inc l ; restore HL
.nextbuf3:
ld a, BUFDATASZ ; move to the next channel info
add a, l
ld l, a
djnz .findloop_buf3
; no buffers have pending data, poll the sockets.
call POLLALL ; poll all open sockets
jr z, .none3 ; nothing waiting
ld (ix+OFS_CURDATA), c ; save socket state
; start with HL pointing at the first potential FD
ld hl, BUFMETADATA+STRM_FLAGS+BUFDATASZ
ld b, 15 ; maximum number of iterations
ld c, a ; store fd
.findloop3:
xor a ; check flags for the stream
cp (hl) ; - for a socket, should all be zero
jr nz, .next3
ld a, c ; check FD = stream's FD
dec l
cp (hl)
jr z, .foundchan3
inc l
.next3:
ld a, BUFDATASZ ; move to the next channel info
add a, l
ld l, a
djnz .findloop3
jr .checkbufs3 ; something not ready for us, but check
; our buffers too.
.bufrdy3:
set BIT_RECV, (ix+OFS_CURDATA)
.foundchan3:
ld a, 16 ; maximum stream number
sub b ; subtract where we got to
ld hl, INTERPWKSPC ; and convert it to a string
call ITOA8
ld (hl), 0 ; add the null
ld hl, INTERPWKSPC ; and send it to BASIC's input buffer.
jp F_sendbuf
.retsockstate3:
ld (ix+OFS_CURSTATE), 0 ; reset state flags
ld a, (ix+OFS_CURDATA) ; get the socket's state
bit BIT_RECV, a ; Received data?
jr nz, .recv3
bit BIT_DISCON, a ; Disconnected?
jr nz, .discon3
bit BIT_CONN, a ; Connected?
jr nz, .connected3
ld hl, STR_unk
jp F_sendbuf
.recv3:
ld hl, STR_recv
jp F_sendbuf
.discon3:
ld hl, STR_discon
jp F_sendbuf
.connected3:
ld hl, STR_conn
jp F_sendbuf
.none3:
ld hl, STR_zero
jp F_sendbuf
;-------------------------------------------------------------------------
; Send the command buffer. Buffer is at (HL)
.globl F_sendbuf
F_sendbuf:
ld a, (hl)
and a ; end of buffer?
jr z, .bufdone4
push hl
rst CALLBAS
defw 0x0F85 ; ZX_ADD_CHAR - put a character into
pop hl ; INPUT's buffer.
inc hl
jr F_sendbuf
.bufdone4:
ld a, 0x0d ; put a CR as the last item
ld l, 0 ; and signal "munge the stack"
scf
jp F_leave ; done.
; Some pre-defined strings to return to BASIC.
STR_badcmd: defb "err Bad command",0
STR_nocmd: defb "err No command",0
STR_unk: defb "unknown",0
STR_recv: defb "recv",0
STR_discon: defb "disconn",0
STR_conn: defb "conn",0
STR_zero: defb "0",0