!
!       NAME:  XTRANS
!
!       FUNCTION:  This is the transmit module for the XMODEM protocol
!       support on the AlphaMicro.  XRECV provides the receive support.
!       First, the receiver sends a NAK sequence to tell the sender to
!       begin transmission.  Then the sender starts sending blocks.  Each
!       block consists of 1) SOH; 2) block number; 3) complemented block
!       number; 4) 128 data bytes; and 5) a one-byte checksum.  The
!       receiver responds with an ACK or a NAK depending on whether or
!       not the block was successfully received.  If not, it is resent.
!       If so, the next block is sent.  When the entire file has been
!       sent, the sender sends an EOT to which the receiver responds with
!       an ACK.  This program may be interrupted by hitting CTL-C three
!       times in a row.
!
!       AUTHOR:  Tom Dahlquist
!
!       EDIT HISTORY:
!         When   Who What
!       01/17/85 TAD Written (from MTRANS).
!       01/24/85 TAD Allow either three DEL's or CTL-C's to kill us.
!
!       This map is for the entire contents of one XMODEM transmission.
!       First is the SOH, then the block #, then the inverted block #,
!       then 128 data bytes, and finally the checksum.
!
       MAP1 WHOLE'BLOCK,X
               MAP2 SOH,X,1,CHR$(1)
               MAP2 BLOCK'NUMBER,B,1,1
               MAP2 NOT'BLOCK'NUMBER,B,1
               MAP2 IO'BLOCK,X,128
               MAP2 CHECK'SUM'BYTE,X,1


       MAP1 BLOCK'LENGTH,F,,128
       MAP1 IN'CHR,X,1
       MAP1 TEST'CHR,X,1
       MAP1 OUT'CHR,X,1
       MAP1 DISK'FSPEC,S,25
       MAP1 OUT'UNIT,F,,0
       MAP1 CHECK'SUM,F
       MAP1 CTRLC,X,1,CHR$(3)
       MAP1 DEL,X,1,CHR$(255)
       MAP1 EOT,X,1,CHR$(4)
       MAP1 ACK,X,1,CHR$(6)
       MAP1 BELL,X,1,CHR$(7)
       MAP1 NAK,X,1,CHR$(21)
       MAP1 ESCAPE,X,1,CHR$(27)
       MAP1 I,F
       MAP1 COUNT'BLOCKS,F
       MAP1 GOT'NAK,F
       MAP1 DEBUG,F
       MAP1 TRUE,F,,-1
       MAP1 FALSE,F,,0
       MAP1 TIMER,F
       MAP1 CHOICE,F
       MAP1 AREA,X,616                 ! for FILEIN
       MAP1 LENGTH,F                   ! from FILEIN and TIMEIN
       MAP1 TIMEOUT,F

GET'FILENAME:
       INPUT LINE "Name of file to be transmitted:  ",DISK'FSPEC
       DISK'FSPEC=UCS(DISK'FSPEC)
       IF DISK'FSPEC[-2,-1]="/D" THEN &
               DISK'FSPEC=DISK'FSPEC[1,-3] : &
               OPEN #99,"XTRANS.LST",OUTPUT : &
               DEBUG=TRUE
       I=INSTR(1,DISK'FSPEC,".")
       IF I=0 THEN DISK'FSPEC=DISK'FSPEC+".DAT"
       LOOKUP DISK'FSPEC,I
       IF I=0 THEN &
               CALL TRY'AGAIN : &
               GOTO GET'FILENAME
       XCALL IMG
       XCALL FILEIN,1,AREA,DISK'FSPEC
!       OPEN #OUT'UNIT, "TRM:", OUTPUT
!
!       We first wait for a NAK from the receiver.  Then we send
!       each block as SOH, block #, inverse block #, 128 data bytes, and
!       a one byte checksum.  Then we wait for an ACK; if we get a NAK,
!       we retransmit the block.  After the last block (of each fork) we
!       send an EOT and wait for an ACK.  That's all folks!
!
START:
       CALL GET'ONE
       IF TIMEOUT GOTO TIMEOUT
       IF IN'CHR=CTRLC THEN &
               CALL CTRLC'ABORT : &
               GOTO START
       IF IN'CHR=DEL THEN &
               CALL DEL'ABORT : &
               GOTO START
       IF IN'CHR#NAK GOTO START
       BLOCK'NUMBER=1
LOOP:
       XCALL FILEIN,2,AREA,IO'BLOCK,LENGTH
       IF LENGTH=0 GOTO EOF
RETRY'BLOCK:
       CALL SEND'BLOCK
       IF GOT'NAK OR TIMEOUT GOTO RETRY'BLOCK
       BLOCK'NUMBER = BLOCK'NUMBER+1
       GOTO LOOP

EOF:
       CALL SEND'EOT
       XCALL FILEIN,3,AREA
       END

SEND'BLOCK:

       NOT'BLOCK'NUMBER=NOT BLOCK'NUMBER

!       CHECK'SUM = 0
!       FOR I = 1 TO 131
!       CHECK'SUM = CHECK'SUM+ASC(WHOLE'BLOCK[I;1])
!       NEXT
!       CHECK'SUM'BYTE=CHR$(CHECK'SUM AND 255)
       XCALL CMPCRC,IO'BLOCK,CHECK'SUM'BYTE

       IF DEBUG THEN &
               ?#99,"-";STR(ASC(SOH)) : &
               ?#99,"-";STR(BLOCK'NUMBER) : &
               ?#99,"-";STR(NOT'BLOCK'NUMBER) : &
               ?#99,"DATA BLOCK" : &
               ?#99,"-";STR(ASC(CHECK'SUM'BYTE))
       PRINT #OUT'UNIT,WHOLE'BLOCK;
       CALL WAIT'ACK
       RETURN

WAIT'ACK:
       GOT'NAK=FALSE
       CALL GET'ONE
       IF TIMEOUT RETURN
       IF IN'CHR = CTRLC THEN &
               CALL CTRLC'ABORT : &
               GOTO WAIT'ACK
       IF IN'CHR=DEL THEN &
               CALL DEL'ABORT : &
               GOTO WAIT'ACK
       IF IN'CHR = NAK THEN &
               GOT'NAK=TRUE : &
               RETURN
       IF IN'CHR <> ACK GOTO WAIT'ACK
       RETURN

SEND'EOT:
       OUT'CHR=EOT
       CALL SEND'ONE
       CALL WAIT'ACK
       IF GOT'NAK GOTO SEND'EOT
       IF TIMEOUT GOTO TIMEOUT
       RETURN

GET'ONE:
       TIMEOUT=FALSE
       XCALL TIMEIN,60,IN'CHR,LENGTH
       IF DEBUG AND LENGTH#0 THEN &
               ?#99,STR(ASC(IN'CHR))
       IF LENGTH=0 THEN TIMEOUT=TRUE
       RETURN

SEND'ONE:
       ?#OUT'UNIT,OUT'CHR;
       IF DEBUG THEN &
               ?#99,"-";STR(ASC(OUT'CHR))
       RETURN

DEL'ABORT:
       TEST'CHR=DEL
       GOTO TEST'ABORT
CTRLC'ABORT:
       TEST'CHR=CTRLC
TEST'ABORT:
       FOR I=1 TO 2
       XCALL TIMEIN,2,IN'CHR,LENGTH
       IF LENGTH=0 OR IN'CHR#TEST'CHR RETURN
       NEXT
       ?"Ending due to operator interrupt!"
       IF DEBUG THEN &
               ?#99,"Ended due to CTL-C"
       END

TIMEOUT:
       ?"Sorry, your Mac isn't talking to me--ending."
       IF DEBUG THEN &
               ?#99,"Timed out."
       END

BAD'FILE:
       END

!===================================================================
TRY'AGAIN:
               ? "That file --- "DISK'FSPEC " --- could not be found. "
               ?
               ? "Would you like to: "
               ? "                   1 -- Try Again! "
               ? "                   2 -- Return to the Menu."
               INPUT " (enter the number of your choice ---  > ", CHOICE
               IF CHOICE=1 RETURN
               IF CHOICE#2 GOTO TRY'AGAIN
               END