; TESTDOOR.COM - the smoke-test door shipped with ATDT DOS doors.
;
; Talks straight to the COM1 UART (0x3F8), polled, no FOSSIL. Proves the
; whole pipeline a real door depends on, one line at a time:
;
;   serial output      the banner reaches the caller's terminal
;   dropfile read      DOOR.SYS is readable over the network drive
;   file write         PROOF.TXT lands in the shared game directory
;   record lock        the redirector lock call answers (multi-node safety)
;   serial input       what the caller types comes back, Q ends the door
;
; Build: nasm -f bin -o TESTDOOR.COM testdoor.asm

        org 0x100

UARTD   equ 0x3F8               ; COM1 data register
UARTLSR equ 0x3FD               ; line status: bit 0 = data ready, bit 5 = THR empty

start:
        mov si, banner
        call puts

        ; ---- dropfile: open DOOR.SYS on the current drive ----
        mov ax, 0x3D00          ; open, read-only
        mov dx, fn_drop
        int 0x21
        jc  .dropfail
        mov bx, ax              ; handle
        mov ah, 0x3F            ; read up to 40 bytes
        mov cx, 40
        mov dx, iobuf
        int 0x21
        pushf
        mov ah, 0x3E            ; close
        int 0x21
        popf
        jc  .dropfail
        mov si, msg_dropok
        call puts
        call putline            ; first line of the dropfile (the COM port)
        jmp .filetest
.dropfail:
        mov si, msg_dropbad
        call puts

        ; ---- write PROOF.TXT and take a record lock on it ----
.filetest:
        mov ah, 0x3C            ; create/truncate
        xor cx, cx
        mov dx, fn_proof
        int 0x21
        jc  .writefail
        mov bx, ax
        mov ah, 0x40            ; write
        mov cx, prooflen
        mov dx, proof
        int 0x21
        jc  .writefail2
        mov si, msg_writeok
        call puts
        ; lock bytes 0..15 (int 21h 5Ch: CX:DX offset, SI:DI length)
        push si
        mov ax, 0x5C00
        xor cx, cx
        xor dx, dx
        xor si, si
        mov di, 16
        int 0x21
        pop si
        jc  .lockfail
        mov si, msg_lockok
        call puts
        push si
        mov ax, 0x5C01          ; unlock the same range
        xor cx, cx
        xor dx, dx
        xor si, si
        mov di, 16
        int 0x21
        pop si
        jmp .closeproof
.lockfail:
        mov si, msg_lockbad
        call puts
.closeproof:
        mov ah, 0x3E
        int 0x21
        jmp .fossil
.writefail2:
        mov ah, 0x3E
        int 0x21
.writefail:
        mov si, msg_writebad
        call puts

        ; ---- FOSSIL: the machine ships one; prove init and block-write ----
.fossil:
        mov ax, 0x0400          ; FOSSIL init
        xor dx, dx
        int 0x14
        cmp ax, 0x1954
        jne .nofossil
        mov si, msg_fossok
        call puts               ; via the raw UART
        push cs
        pop  es                 ; and this line via the driver itself
        mov di, msg_fosstx
        mov cx, fosstx_len
        mov ah, 0x19
        xor dx, dx
        int 0x14
        jmp .echo
.nofossil:
        mov si, msg_fossbad
        call puts

        ; ---- echo loop: type and see it come back, Q ends the door ----
.echo:
        mov si, msg_prompt
        call puts
.echoloop:
        call getc
        cmp al, 'Q'
        je  .bye
        cmp al, 'q'
        je  .bye
        call putc
        cmp al, 13              ; CR gets a LF so lines look right
        jne .echoloop
        mov al, 10
        call putc
        jmp .echoloop

.bye:
        mov si, msg_bye
        call puts
        mov ax, 0x4C00
        int 0x21

; ---- serial helpers (polled UART, COM1) -------------------------------

; putc: send AL out the UART, waiting for the transmitter first.
putc:
        push ax
        push dx
        mov ah, al
        mov dx, UARTLSR
.wait:
        in  al, dx
        test al, 0x20           ; THR empty?
        jz  .wait
        mov dx, UARTD
        mov al, ah
        out dx, al
        pop dx
        pop ax
        ret

; getc: block until a byte arrives, return it in AL.
getc:
        push dx
        mov dx, UARTLSR
.wait:
        in  al, dx
        test al, 0x01           ; data ready?
        jz  .wait
        mov dx, UARTD
        in  al, dx
        pop dx
        ret

; puts: send the ASCIIZ string at SI.
puts:
        push ax
.next:
        lodsb
        test al, al
        jz  .done
        call putc
        jmp .next
.done:
        pop ax
        ret

; putline: send iobuf up to the first CR/LF/NUL (max 40), then CRLF.
putline:
        push ax
        push si
        mov si, iobuf
        mov cx, 40
.next:
        lodsb
        test al, al
        jz  .done
        cmp al, 13
        je  .done
        cmp al, 10
        je  .done
        call putc
        loop .next
.done:
        mov al, 13
        call putc
        mov al, 10
        call putc
        pop si
        pop ax
        ret

; ---- data -------------------------------------------------------------

banner      db 13, 10, '[ATDT-TESTDOOR] node online', 13, 10, 0
msg_dropok  db 'DROPFILE OK: ', 0
msg_dropbad db 'DROPFILE FAIL', 13, 10, 0
msg_writeok db 'WRITE OK', 13, 10, 0
msg_writebad db 'WRITE FAIL', 13, 10, 0
msg_lockok  db 'LOCK OK', 13, 10, 0
msg_lockbad db 'LOCK FAIL', 13, 10, 0
msg_fossok  db 'FOSSIL OK', 13, 10, 0
msg_fossbad db 'FOSSIL MISSING', 13, 10, 0
msg_fosstx  db 'FOSSIL-TX OK', 13, 10
fosstx_len  equ $ - msg_fosstx
msg_prompt  db 'Type and watch it echo. Q hangs up.', 13, 10, '> ', 0
msg_bye     db 13, 10, '[ATDT-TESTDOOR] bye', 13, 10, 0
fn_drop     db 'DOOR.SYS', 0
fn_proof    db 'PROOF.TXT', 0
proof       db 'written by TESTDOOR over the network drive', 13, 10
prooflen    equ $ - proof

iobuf       resb 64
