!
! NAME: MTRANS
!
! FUNCTION: This is the transmit module for the MacTerminal protocol
! support on the AlphaMicro. MRECV provides the receive support.
! This protocol is similar to and uses the same as XMODEM protocol.
! First, the sender sends an escape sequence to tell the receiver to go
! into receive mode. Then it sends the file information block in standard
! XMODEM format, then an EOT. Then XMODEM protocol is used twice, all
! the way from the beginning NAK from the receiver to the ending
! EOT from the sender and ACK from receiver; the first time the data
! fork is sent; then the resource fork.
!
! AUTHOR: Tom Dahlquist
!
! EDIT HISTORY:
! When Who What
! 11/10/84 TAD Written (from XTRANS).
! 01/16/84 TAD Several changes. 1) Use FILEIN for input from file, thus
! allowing us to use RUN instead of XRUN. 2) Use TIMEIN
! for input from terminal, allowing timeouts. 3) Ignore
! CTL-C unless three of them hit in a row. 4) Fix little
! bug in TRY'AGAIN.
! 01/24/85 TAD Accept either three DEL's or CTL-C's to kill us.
! 05/09/85 TAD Use CMPCRC to compute CRC.
!
! 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
!
! This is the map of the file information block sent by MacTerminal.
! The filler byte sent after the SOH, block #, inverted block # has
! been kept as the first byte of the block for simplicity, since the
! AlphaMicro doesn't really care about alignment.
!
MAP1 FILE'INFO,@IO'BLOCK
MAP2 FILL1,X,1 ! first filler byte
MAP2 FNAME,X,64 ! MacIntosh file name
MAP2 FTYPE,S,4 ! file type
MAP2 FCREATE,S,4 ! file creator
MAP2 FFLAGS,B,2 ! file flags
MAP2 FLOC,B,4 ! location in folder
MAP2 FFOLDER,B,2 ! file folder
MAP2 LOCKED,B,2 ! locked flags
MAP2 DSIZE,X,4 ! size of data fork
MAP2 RSIZE,X,4 ! size of resource fork
MAP2 FLCRDAT,B,4 ! creation date
MAP2 FLMDDAT,B,4 ! modification date
MAP2 FILL2,X,29 ! filler
GET'FILENAME:
DISK'FSPEC=""
INPUT LINE "Name of file to be transmitted: ",DISK'FSPEC
IF DISK'FSPEC="" GOTO GET'FILENAME
IF UCS(DISK'FSPEC[-2,-1])="/D" THEN &
DISK'FSPEC=DISK'FSPEC[1,-3] : &
OPEN #99,"MTRANS.LST",OUTPUT : &
DEBUG=TRUE
DISK'FSPEC=UCS(DISK'FSPEC)
I=INSTR(1,DISK'FSPEC,".")
IF I=0 THEN DISK'FSPEC=DISK'FSPEC+".MAC"
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
!
! Transfer starts with sender (us) sending "ESC a" sequence to the
! receiver, then wait for an ACK. Then the first block is sent
! in standard XMODEM block format. Then we wait for an ACK. Then
! we send an EOT and wait for an ACK. NOTE: since for some
! unfathomable reason the current version of MacTerminal (1.1) will
! not retransmit the file information block if a NAK is received,
! we will duplicate that behavior here.
!
OUT'CHR=ESCAPE
CALL SEND'ONE
OUT'CHR="a"
CALL SEND'ONE
CALL WAIT'ACK
IF GOT'NAK GOTO CLOSE'UP
IF NOT TIMEOUT GOTO NT1
IF DEBUG THEN &
?#99,"Timed out waiting for ACK after header"
GOTO TIMEOUT
NT1:
XCALL FILEIN,2,AREA,IO'BLOCK,LENGTH
IF LENGTH#BLOCK'LENGTH GOTO BAD'FILE
TIMER=TIME+2
WAIT:
IF TIME<TIMER GOTO WAIT
CALL SEND'BLOCK
IF GOT'NAK GOTO CLOSE'UP
CALL SEND'EOT
!
! Now we send the data and resource forks, in that order. Each
! fork is sent using the complete XMODEM protocol. That means that
! we have to 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! Note one
! little thing--the block count IS reset at the beginning of each fork.
!
TEMP1=DSIZE
CALL MASSAGE
SIZED=TEMP'SIZE
TEMP1=RSIZE
CALL MASSAGE
SIZER=TEMP'SIZE
SIZE=SIZED
CALL SEND'SEGMENT
SIZE=SIZER
CALL SEND'SEGMENT
XCALL FILEIN,3,AREA
GOTO CLOSE'UP
!
SEND'SEGMENT:
CALL GET'ONE
IF NOT TIMEOUT GOTO NT2
IF DEBUG THEN &
?#99,"Timed out waiting for NAK at beginning of fork"
GOTO TIMEOUT
NT2:
IF IN'CHR=CTRLC THEN &
CALL CTRLC'ABORT : &
GOTO SEND'SEGMENT
IF IN'CHR=DEL THEN &
CALL DEL'ABORT : &
GOTO SEND'SEGMENT
IF IN'CHR#NAK GOTO SEND'SEGMENT
BLOCK'NUMBER=1
NUM'BLOCKS=INT(SIZE/BLOCK'LENGTH)
IF NUM'BLOCKS*BLOCK'LENGTH#SIZE THEN NUM'BLOCKS=NUM'BLOCKS+1
IF NUM'BLOCKS=0 GOTO NO'DATA
FOR COUNT'BLOCKS=1 TO NUM'BLOCKS
XCALL FILEIN,2,AREA,IO'BLOCK,LENGTH
IF LENGTH#BLOCK'LENGTH GOTO BAD'FILE
NAK'COUNT=0
TIMEOUT'CNT=0
RETRY'BLOCK:
CALL SEND'BLOCK
IF GOT'NAK THEN &
NAK'COUNT=NAK'COUNT+1 : &
IF NAK'COUNT=5 GOTO CLOSE'UP &
ELSE GOTO RETRY'BLOCK
IF NOT TIMEOUT GOTO NT3
TIMEOUT'CNT=TIMEOUT'CNT+1
IF DEBUG THEN &
?#99,"Timed out waiting for ACK after this block"
IF TIMEOUT'CNT=3 GOTO TIMEOUT
GOTO RETRY'BLOCK
NT3:
BLOCK'NUMBER = BLOCK'NUMBER+1
NEXT COUNT'BLOCKS
NO'DATA:
CALL SEND'EOT
RETURN
SEND'BLOCK:
NOT'BLOCK'NUMBER=NOT BLOCK'NUMBER
CHECK'SUM = 0
! FOR I = 1 TO BLOCK'LENGTH
! CHECK'SUM = CHECK'SUM+DATA'BYTES(I)
! NEXT
! CHECK'SUM'BYTE=CHR$(CHECK'SUM AND 255)
XCALL CMPCRC,IO'BLOCK,CHECK'SUM'BYTE
DRAIN:
XCALL TIMEIN,0,DRAIN'BUF,LENGTH
IF LENGTH=20 GOTO DRAIN
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 NOT TIMEOUT RETURN
IF DEBUG THEN &
?#99,"Timed out waiting for ACK after EOT"
GOTO TIMEOUT
MASSAGE:
FOR I=1 TO 4
TEMP2X(5-I)=TEMP1X(I)
NEXT
RETURN
GET'ONE:
START'TIME=TIME
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 : &
IF DEBUG THEN ?#99,"Time=";STR(TIME-START'TIME)
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!"
GOTO CLOSE'UP
TIMEOUT:
?"Sorry, your Mac isn't talking to me--ending."
GOTO CLOSE'UP
BAD'FILE:
GOTO CLOSE'UP
CLOSE'UP:
IF DEBUG THEN CLOSE #99
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