;*************************** AMUS Program Label ******************************
; Filename: XM.M68 Date: 07/15/91
; Category: UTIL Hash Code: 736-155-127-460 Version: 4.0(100)
; Initials: ULTR/US Name: DAVID PALLMANN
; Company: ULTRASOFT CORPORATION Telephone #: 5163484848
; Related Files:
; Min. Op. Sys.: AMOSL 1.3B/AMOS32 1.0 Expertise Level: INT
; Special: Replaces X.LIT to avoid conflict with other programs named X
; Description: XMODEM slave program - see XM.WRT for definition of protocol
; This program is also distributed as part of TALKTO 4.0.
; Copyright (C) 1991 UltraSoft Corporation
;*****************************************************************************
;****************************************************************************
;* *
;* XM *
;* XMODEM slave program *
;* *
;****************************************************************************
;Copyright (C) 1991 UltraSoft Corporation. All Rights Reserved.
;
;Written by: David Pallmann
;
;Edit History:
;[100] 4.0(100) Created. /DFP
VMAJOR =4
VMINOR =0
VSUB =0
VEDIT =100.
VWHO =0
;universals
SEARCH SYS
SEARCH SYSSYM
SEARCH TRM
;error codes
ER$BLK =1 ; block number wrong
ER$COM =2 ; complemented block number wrong
ER$CRC =3 ; CRC wrong
;ASCII character definitions
SOH =1 ; Start of Header
EOT =4 ; End of Transmission
ACK =6 ; ACKnowledge
CR =13. ; Carriage Return
NAK =21. ; Negative AcKnowledge
;communications parameters
BLKSIZ =128. ; data packet size (bytes)
RETRY =10. ; max retry count
;XMODEM communications block structure
.OFINI
.OFDEF X.SOH, 1 ; SOH byte (or EOT on end of file)
.OFDEF X.BLK, 1 ; block number
.OFDEF X.COM, 1 ; complemented block number
.OFDEF X.DAT, BLKSIZ ; data area
.OFDEF X.CRC, 1 ; CRC byte
.OFSIZ X.SIZ
R.RDY: MOVB #NAK,D1 ; send NAK to indicate we are ready
CALL $PTBYT ;
MOV #10.*100.,D0 ; 10 second wait loop
10$: CALL $CKINP ;
BEQ R.GET ;
SLEEP #100. ;
SOB D0,10$ ;
BR R.RDY ;
;get block of data
;wait for initial SOH or EOT
R.GET: MOV #10.*100.,D0 ; set 10 second loop count
5$: CALL $CKINP ; character received?
BEQ 6$ ; yes
SLEEP #100. ; no - sleep 1/100 second
SOB D0,5$ ; loop until time-out or char rcvd
JMP R.NAK ; send an ACK
6$: CALL $GTBYT ; get character
CMPB D1,#SOH ; SOH?
BEQ R.RCV ; yes - start of a comm. block
CMPB D1,#EOT ; EOT?
JEQ R.EOF ; yes - end of file
BR R.GET ; discard byte and wait for another
;we've gotten the start of a communications block - receive the rest of it
R.RCV: MOV #1+2+BLKSIZ+1,D2 ; set block size loop count
LEA A0,DATA(A5) ; index comm. block storage area
BR 40$ ; go store SOH we just received
10$: MOV #10.*100.,D0 ; 10 second wait loop
20$: CALL $CKINP ; character received?
BEQ 30$ ; yes
SLEEP #100. ; no sleep 1/100 second
SOB D0,20$ ; loop until timeout exceed or char rcvd
CMP D2,#1+2+BLKSIZ+1 ; did we get anything?
JEQ R.NAK ; no - send NAK
CMPB X.SOH(A4),#EOT ; did we get an EOT?
JEQ R.EOF ; yes - end of file
JMP R.NAK ; send NAK
30$: CALL $GTBYT ; get character
40$: MOVB D1,(A0)+ ; store it
SOB D2,10$ ; loop until entire block received
;we've gotten a full data block
R.CHK: MOVB #ER$BLK,ERRCOD(A5) ;
CMPB D4,X.BLK(A4) ; right block number?
JNE R.NAK ; no - send NAK
MOVB #ER$COM,ERRCOD(A5) ;
MOV D4,D7 ; copy block number
COM D7 ; and complement it
CMPB D7,X.COM(A4) ;
BEQ R.CRC ;
AND #177,D7 ;
CMPB D7,X.COM(A4) ; right complemented block number?
JNE R.NAK ; no - send NAK
;check CRC of block data
R.CRC: MOVB #ER$CRC,ERRCOD(A5) ;
LEA A0,X.DAT(A4) ; index data area of block
MOV #BLKSIZ,D0 ; load block size
CLR D5 ; pre-clear CRC
CLR D1 ; clear d1
10$: MOVB (A0)+,D1 ; get byte
ADDW D1,D5 ; add to checksum
SOB D0,10$ ; loop until done
CMPB D5,X.CRC(A4) ; right checksum?
BEQ R.WRT ;
MOVB D5,D7 ;
AND #177,D7 ;
CMPB D7,X.CRC(A4) ;
JNE R.NAK ; no - send NAK
;write out data to file
R.WRT:
;check for ^Z and nulls at end of buffer
TSTB BINFLG(A5) ; is this file text or binary?
BNE 5$ ; binary - don't strip anything
LEA A6,X.DAT+BLKSIZ(A4) ;
MOV #BLKSIZ-1,D0 ;
2$: TSTB -(A6) ;
BNE 3$ ;
SOB D0,2$ ;
3$: CMPB @A6,#'Z-'@ ;
BEQ R.PAR ;
5$: LEA A0,X.DAT(A4) ; index data area of block
MOV #BLKSIZ,D0 ; load block size
10$: MOVB (A0)+,D1 ; get byte
CMPB D1,#200 ; 8-bit byte?
BLO 20$ ; no
MOVB #1,BINFLG(A5) ; yes - set binary flag
20$: FILOTB FILE(A5) ; write it out
SOB D0,10$ ; loop
BR R.ACK ;
R.PAR: DEC D0 ;
BEQ R.ACK ;
LEA A0,X.DAT(A4) ;
10$: MOVB (A0)+,D1 ;
FILOTB FILE(A5) ;
SOB D0,10$ ;
;send ACK to acknowledge receipt of good data block
R.ACK: CLRW RETCNT(A5) ; clear retry count
MOVB #ACK,D1 ; send ACK (we like the block)
CALL $PTBYT ;
INCW D4 ; update block number
JMP R.GET ; go get next block
;send NAK to reject block and indicate retransmission is necessary
R.NAK: INCW RETCNT(A5) ;
CMPW RETCNT(A5),#RETRY ;
JHIS R.ERR ;
MOVB #NAK,D1 ; send NAK, we reject the block
CALL $PTBYT ;
JMP R.GET ; go get block again
;end of file - close file and exit
R.EOF: MOVB #ACK,D1 ; send final ACK
CALL $PTBYT ; back to sender
CLOSE FILE(A5) ;
10$: CALL $GTBYT ;
CMPB D1,#CR ;
BNE 10$ ;
TYPECR [ File Received Succesfully ]
EXIT ;
R.ERR: CLOSE FILE(A5) ;
DSKDEL FILE(A5) ;
10$: CALL $GTBYT ;
CMPB D1,#'D ;
JEQ DUMP ;
CMPB D1,#CR ;
BNE 10$ ;
TYPECR [ Maximum Number of Retries Exceeded ]
;************
;* $GTBYT *
;************
;Function: Get byte from modem port (terminal version)
;
;Inputs: none
;
;Outputs: D1 - byte
$GTBYT: TIN ;
RTN ;
;************
;* $PTBYT *
;************
;Function: Put byte to modem port (terminal version)
;
;Inputs: D1 - byte to send
;
;Outputs: none
$PTBYT: TTY ;
RTN ;
;************
;* $CKINP *
;************
;Function: Check port for input
;
;Inputs: none
;
;Outputs: Z - set if there is input; cleared if there is no input
$CKINP: TCKI ; set Z if there is input else clear it
RTN ; return with Z set or cleared