home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
alphamicro.zip
/
am68k.m68
< prev
next >
Wrap
Text File
|
1994-03-18
|
112KB
|
3,548 lines
; Kermit.m68 - a telecommunications & error free file transfer program
; Version 2.0 - supports wildcarding, 3 byte CRC
; Author: Robert P. Rubendunst, Soft Machines,
; P.O. box 3701, Champaign, IL 61821
; Copyright 1984, 1991 Robert P. Rubendunst. All rights reserved. In
; addition, anthology copyrights prohibited without written permission from
; the author.
; N O T E - requires 1.3D AMOS/L//1.0D AMOS/32 or later to assemble.
; To assemble, M68 KERMIT.m68 produces KERMIT.LIT
; Edit History:
;[024] 16 March 1994 13:45 Edited by Bob Rubendunst
; Added test & message when re-entering user tries to
; re-specify port name.
;[023] 31 January 1992 10:49 Edited by Bob Rubendunst
; Corrected problems in RPAR which caused file transfers to fail.
;[022] 10 January 1992 09:37 Edited by Bob Rubendunst
; Added logic to strip CONNECT to 7 bits if PARITY is not NONE.
;[021] 09 January 1992 09:37 Edited by Bob Rubendunst
; Documentation changes in CONNECT message
; Added TIMEOUT and ENDLINE parametes to SET parameters list in SHOW
; Changed SHOCHR to always display 3 characters, show ^ as dim if ctl
; fixed problem with outputting zero byte files
; improved SPAR & RPAR logic to handle 7 bit cases better.
;[020] 31 December 1991 11:06 Edited by Bob Rubendunst
; Added code to make CONNECT mode compatible with 8 bit terminals.
; (Exit character must match all 8 bits if TDV presents TD$EXT)
; Deleted BPT legerdemain and just used SUPVR instead in SETSTS!
;[019] 31 December 1991 10:41 Edited by Bob Rubendunst
; AUTORECEIVE feature completed
;[018] 06 December 1991 13:08 Edited by Bob Rubendunst
; Added random file bypass for batch SENDing.
; Added code to eliminate possible bogus packet timeout at midnight.
; Added command line help.
; Added SET PARITY input checking
;[017] 02 December 1991 11:48 Edited by Bob Rubendunst
; Added SET PACKETSTART option
; Deleted code to save & restore jcb jobtyp word (not used)
;[016] 22 November 1991 13:27 Edited by Bob Rubendunst
; Added AUTORECEIVE command
; Changed SEND logic to send a Break packet if no files sent.
; Corrected some help text with Karen Bojda's help.
; Streamlined INUSE subroutine
; Added code to revive job when attaching JCB & TCB
; Completed graceful abort code for SENDing
; Corrected tests for maximum retries - some were BNE instead of BLOS
;[015] 31 October 1991 16:49 Edited by Bob Rubendunst
; Added wildcarding via CMDLIN.SYS. Kudos to Tom Niccum of KW fame.
; Added totals statistics.
; Added code to make SEND automatically send KERMIT and REC commands
; to remote Kermit. Can be de-activated with SET AUTOSEND OFF.
; Changed filenames to lower case for Unix compatibility.
; Added 3 byte CRC check type. Should eliminate problems with
; PC Kermits that do 2 byte CRCs wrong (Select either 1 or 3 byte option
; in Procomm Plus - vers 2.0 STILL does 2 byte checksums wrong.)
; Added SY$M40 symbol for possible AM4000 machine.
; Added code to avoid T.SEM problems with smart I/O cards
; Enhanced file size calcs to work under extended directories
; Added file closes to make compatible with AMOS 2.x
; Kermit only delays five seconds before SENDING in REMOTE mode instead
; of fifteen.
; Changed VMAJOR to 2.
;[014] 28 March 1991 12:38 Edited by Bob Rubendunst
; Added routine to adjust sleep value for faster baud rates.
; Note that this does improve performance at higher baud rates,
; especially for file transfers. Due to limitations in TTYIN monitor
; call, Kermit can still lose characters at higher baud rates.
; Fixed bug in effective baud rate calculation when calculating
; date rollover at midnight.
;[013] 28 March 1991 12:08 Edited by Bob Rubendunst
; Corrected problems with received filenames being expanded to 6 & 3
; even if they were shorter.
; Fixed problem in edit 12 with max packetsize not being defaulted
; at startup.
;[012] 06 February 1990 09:23 Edited by Bob Rubendunst
; Corrected a few bugs in checking for previous or next packet
; needing to be ACKed. Also fixed parameter display to display
; active END-OF-LINE caharcter, rather than default end-of-line.
;[011] 02 Dec 1988
; made compare for ESCAPE character 7 bits instead of 8 bits
; added BLOCKSIZE to SET command
;[010] 11 Sept 1988
; Changed handling of port busy bit so that REMOTE users do not monitor
; or change the terminal busy bit. Defines new SY$ symbols for 68020 &
; 68030 if not already defined.
;[009] 29 Jun 1988
; Completed basic compatibility with AM3000 systems
;[008] May 1988
; Started compatibility with AM3000 systems.
;[007] 24 Oct 1986
; Changed CONNEC routine to properly set T.DAT bit and T.XLT bits so
; nulls can be sent from keyboard.
;[006] 29 Jul 1986
; Tidied up SHOW command, added dot for every packet of data sent or
; rec'd, SET ? now shows SET list.
;[005] ??
; Change Kermit to accept running under AMOS/32. rpr
;[004] 12 May 1986
; straightened out 8-bit quoting problem in RPAR
; updated INUSE bit to use new bit under 1.3B
; transformed SET BINQUOTE feature into SET PARITY feature
; (does not set parity, but info is used to determine 7 or 8 bit modes.)
; corrected checkbyte size detection problem when used with unix c
; where ACK to F contained new filename under c. Alpha-Kermit thought
; this was an ACK to an I packet and used the wrong checkbyte type.
; Fixed 255 to 255. in max retries entry code 6/27/85 rpr
; Fix requires keeping track of the ACKing of the I packet via RIACK(A0)
; Fixed QBIN not defined on short received SINIT packet 4/24/85 rpr
; AMUS release (clean-up same TCB use) 12/3/84 rpr
; Added 7 bit mode to allow use with ELS... 10/23/84 rpr
; First non-alpha transfers 10/5/84 with ibm pc
;[000] 07 Sept 1984 project begun
; Permission is granted to any individual or institution to copy or use this
; software and the routines described in it, except for explicitly commercial
; purposes. This software must not be sold to any person or institution.
;;;;;;;;;;;;;;;;;;;;;;;;;;;; D I S C L A I M E R ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; No warranty of the software or of the accuracy of the documentation ;;
;; surrounding it is expressed or implied, and neither the authors, ;;
;; Columbia University, Soft Machines, or AMUS acknowledge any liability ;;
;; resulting from program or documentation errors. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; usage format:
; KERMIT <terminal-name> <escape character>
; then enter ? or HELP for use hints.
SEARCH SYS
SEARCH SYSSYM
SEARCH TRM
COPY CMDSYM
IF NDF,SY$M20, SY$M20 = ^O20000 ; supply missing symbols [010]
IF NDF,SY$M30, SY$M30 = ^O100000 ; supply missing symbols [010]
IF NDF,SY$M40, SY$M40 = ^O2000000000 ; support possible 68040 [015]
IF NDF,SY$EXT, SY$EXT = ^O10000000 ; support 8 bit terminals [021]
IF NDF,TD$EXT, TD$EXT = ^O1000000000 ; support 8 bit terminals [021]
IF NDF,T$EXT, T$EXT = ^O20000 ; support 8 bit terminals [021]
; supplementary symbols for finding file type & size
D.LEN=D.WRK
D.ACT=D.LEN+4
D.1ST=D.ACT+10
; symbols to define byte-word-lword relationships
; The Alpha Micro uses byte-swap logic to switch the sense of UDS & LDS
; in hardware, so that BYTE ACCESS of data is the opposite of normal 68000s.
; (This was done because the WD-16 processor used Intel style byte access,
; were the MSB of a word is stored at higher addresses. Motorola CPUs
; store words MSB at lower addresses.)
; (WORD & LWORD ACCESS is not affected, only BYTE ACCESS.)
; (change these definitions for non-AM style hardware!!)
.B0W7 = 0 ; access LS byte of a 16 bit word
.B8W15 = 1 ; access MS byte of a 16 bit word
.B0L7 = 2 ; access bits 00-07 of a 32 bit word
.B8L15 = 3 ; access bits 08-15 of a long word
.B16L23 = 0 ; access bits 16-23 of a long word
.B24L31 = 1 ; access bits 24-31 of a long word
.W0L15 = 2 ; access LS word of long word
.W16L31 = 0 ; access MS word of long word
; symbol definitions
TRUE = -1
FALSE = 1
PAKSIZ = 94. ; max packet size
SOH = 1. ; default MARK character
CR = 13. ; ASCII carriage return
SPACE = 32. ; ASCII SP
DEL = 127. ; ASCII DEL
ESCCHR = '^ ; default escape character
A.BEL = 7. ; ASCII bell [24]
TRIES = 10. ; number of packet tries
MYQUOT = '# ; control-quoting
MYPAD = 0 ; number of pad chars
MYPCHR = 0 ; the pad character I need
MYEOL = 0 ; my end of line character
MYTIME = 08. ; seconds before timeout
MYBIN = 'Y ; binary qoute mode
MYCHK = '3 ; try to use 3 byte check bytes
MAXCHK = 3 ; maximum check type supported
MAXTIM = 60. ; maximum timeout
MINTIM = 2 ; minimum timeout period
; This macro is used to read a packet
DEFINE RPACK LEN,SEQ,PACKET,TYPE
LEA A3,PACKET
CALL RECPAK
SSTS D7
MARG MOVB, D2,LEN
MARG MOVB, D3,SEQ
MARG MOVB, D4,TYPE
LCC D7
ENDM
; This macro sends a packet to the REMOTE
DEFINE SPACK TYPE,SEQ,SIZE,PACKET
LEA A3,PACKET
CCLR SIZE,D2
CCLR SEQ,D3
CCLR TYPE,D4
MARG MOVB, SIZE,D2
MARG MOVB, SEQ,D3
MARG MOVB, TYPE,D4
CALL SNDPAK
ENDM
; This macro assembles argument linkage opcodes only where the default
; argument is not used. This provides more readable code without adding
; unnecessary instructions.
; For example, if D2 is the standard data link register, the macro
; MARG MOVW D2,D2
; will not produce an assembly line, but
; MARG MOVW D2,D3
; will assemble the line MOVW D2,D3
DEFINE MARG OPCODE, SRC, DST
NTYPE ...X,SRC
NTYPE ...Y,DST
IF NE,...X-...Y,OPCODE SRC,DST
ENDM
ASECT
; This macro is used to pre-clear result variables before a packet call
; IF they are not registers.
DEFINE CCLR ARG,REG
NTYPE ...D,ARG
NTYPE ...E,REG
IF NE,...D-...E,CLR REG
ENDM
.=0
; define the impure area for KERMIT.
NOSYM
; CONNECT command variables and general REMOTE/LOCAL channel variable
TNAME: BLKW 2 ; terminal name packed RAD50
SAVTDV: BLKL 1 ; address of saved TDV
PSEUDO: BLKL 1 ; address of PSEUDO driver
SAVSTS: BLKW 1 ; saved TCB status
SAVJCB: BLKL 1 ; saved attached JCB index
REMOTE: BLKL 1 ; index to remote TCB
LOCAL: BLKL 1 ; index to local TCB
STIME: BLKL 1 ; start time of event
FSIZE: BLKL 1 ; size of file in bytes
KMETA: BLKB 1 ; escape character
DONE: BLKB 1 ; done with kermit flag
NOTALK: BLKB 1 ; flag that remote TCB is job's.
ECHO: BLKB 1 ; duplex flag 0 for full, 377 for half
CCOUNT: BLKB 1 ; control-c count
AUTOS: BLKB 1 ; autosend option for SEND
AUTOR: BLKB 1 ; AUTORECEIVE option for REC
COMSER: BLKB 1 ; flag -1 if COMSER routines O.K.
EXTEND: BLKB 1 ; extended device support flag
ABORTB: BLKB 1 ; -1 if send batch to be aborted
ABORTF: BLKB 1 ; -1 if send file to be aborted
WILDOK: BLKB 1 ; -1 if wildcarding O.K.
CMASK: BLKB 1 ; bit mask for 7 or 8 bit characters
CFLAG: BLKB 1 ; flag we have breifed user on CONNECT
ATERM: BLKB 7 ; terminal name in ASCII & null
EVEN
FIO: BLKB D.DDB ; file I/O ddb area
SIO: BLKB D.DDB ; ddb just for file spec & cmdlin
; KERMIT packet receiver variables
ASSUM: BLKW 1 ; checksum storage
FRMSUM: BLKW 1 ; CRC storage
RTOUT: BLKL 1 ; time's up in seconds from midnight.
FUDGE: BLKL 1 ; fudge factor for midnight wrap-around
TIMINT: BLKL 1 ; # of seconds for timeout on sends
DF.TIM: BLKL 1 ; default timeout
; Global variables for file section
LOGIC: BLKB 1 ; 1=false, -1=true
LDATA: BLKB 1 ; size of present data
SPSIZ: BLKB 1 ; max send packet size
PAD: BLKB 1 ; # of padding chars to send
PADCHR: BLKB 1 ; pad character
EOL: BLKB 1 ; EOL character to send
N: BLKB 1 ; packet number
MAXTRY: BLKB 1 ; max # of tries
NUMTRY: BLKB 1 ; times this packet retried
OLDTRY: BLKB 1 ; times previous packet retried
BUFCNT: BLKB 1 ; # of data bytes for packet
DEBUGO: BLKB 1 ; level of debug output (0=none)
DING: BLKB 1 ; ding after each command flag (#0=yes)
DF.EOL: BLKB 1 ; default EOL character
DF.CHK: BLKB 1 ; default check type character
PARITY: BLKB 1 ; parity mode (None, Odd, Even, Space.)
STATE: BLKB 1 ; present state of file transfer automaton
QUOTE: BLKB 1 ; incoming quote char
QBIN: BLKB 1 ; storage & flag controlling 8 bit quoting:
; 0 indicates 8 bit path, no quoting
; -1 indicates 7 bit path, no quoting
; all other values 33.-62. 96.-126. are valid
; 8 bit quote characters (usually &)
CHKT: BLKB 1 ; checkbyte method as ascii character
CHKNOW: BLKB 1 ; checkbyte in use for this packet
REPT: BLKB 1 ; repeat byte (not implemented yet)
FLLEN: BLKB 1 ; filename length
RMARK: BLKB 1 ; the MARK character
RIACK: BLKB 1 ; flag we got an ACK to an I packet
MXPKSZ: BLKB 1 ; maximum packet size allowed
STLCHR: BLKB 1 ; stall character time in 100ths of a second
RECPKT: BLKB PAKSIZ ; buffer for receiving packets
PACKET: BLKB PAKSIZ ; another one
NFILNM: BLKB 4 ; room for MARK,LEN,SEQ,TYPE
FILNAM: BLKB 60. ; current filename
BLKB 20.
COPY: BLKB 60. ; ; copied filename
BLKB PAKSIZ-80.
EVEN
SLPVAL: BLKL 1 ; sleep value in ticks for GETREM routine
TFILES: BLKL 1 ; total files sent or received
TBYTES: BLKL 1 ; total bytes in files sent or received
TTIME: BLKL 1 ; total elapsed times
CLDDB: BLKB D.DDB ; CMDLIN.SYS ddb area
CMDERR: BLKL 1 ; CMDLIN.SYS .CMINI error cod
CMDPTR: BLKL 1 ; ptr to CMDLIN.SYS module
SAVSPC: BLKL 1 ; ptr to user's command line
CMNEXT: BLKL 1 ; saved flags from CM.NXT in CMDLIN routines
NXTCNT: BLKB 1 ; count of times NXTSPC called w/o wildcard
CMDFLG: BLKB 1 ; flag we have CMDLIN.SYS
EVEN
CMDIMP: BLKB IMP.SZ+100. ; room for CMDLIN.SYS
EVEN
KSIZE=.
.=0
; definition of KERMIT packet offsets
MARK: BLKB 1 ; the MARK character
LEN: BLKB 1 ; received LEN
SEQ: BLKB 1 ; received sequence
TYPE: BLKB 1 ; received type
DATA: BLKB 1 ; beginning of DATA
; 1, 2, or 3 byte check bytes follow the data and end the packet
.=0
SYM
REMMOD = T$IMI!T$ECS!T$DAT ; IMAGE, NOECHO mode bits
; The following macros define character tranlation functions needed to
; implement the KERMIT protocol.
; MACROs to perform CHAR, UNCHAR & CTL functions via register argument.
; C H A R - change control character to printable character
DEFINE CHAR DST
ADDB #SPACE,DST
ENDM
; U N C H A R -change CHARed control character back into a control character
DEFINE UNCHAR DST
SUBB #SPACE,DST
ENDM
; CTL - UNCONTROLIFY a CHARACTER. CTL(CTL(CHAR)) leaves CHAR unchanged.
DEFINE CTL DST
XORB #64.,DST
ENDM
PSECT
; K E R M I T
; Main Kermit routine. The first time executed, KERMIT builds its impure area,
; KERMIT.IMP. Then the main routine accepts and performs user commands.
;
VMAJOR =2
VMINOR =0
VSUB = 0
VEDIT = 024.
VWHO =0
RADIX 8. ; default numbers in octal
KERMIT: PHDR -1,PV$RSM!PV$WSM!PV$RPD!PV$WPD,PH$REE!PH$REU
CMPB @A2,#'/ ; flag?
BNE 2$
INC A2
CMPB @A2,#'? ; help?
BEQ 1$
TTYI
ASCII "undefined switch - assuming /? switch"
BYTE CR,A.BEL,0
EVEN
1$: TTYL USAGE
EXIT
; make sure we are running under an OS that supports TTYOUT.
2$: CALL KERTTL ; show title and version
MOV SYSTEM,D5 ; get system word
AND #SY$M20!SY$M30!SY$M40,D5 ; mask to just AMOS/32
BNE 10$ ; we are on AMOS/32, has TTYOUT
CMPB PH.VER+.B8W15,#1. ; MAJOR higher than 1?
BHI 10$ ; yes-use new value
MOVB PH.VER+.B16L23,D5 ; no- get sub release
ANDB #^O17,D5 ; strip out VWHO in top 4 bits
CMPB D5,#2. ; is this 1.2 or later?
BHIS 10$ ; yes- we can execute
; no- time to update the system!
TTYI
ASCII "%This software requires AMOS/L 1.2 or later O/S."
BYTE CR,0
EVEN
EXIT
10$: CALL INIMEM ; initial memory area
BNE EXEUNT ; need more memory-abort
BMI 20$ ; TCB already assigned
; first time entry. Check for CONNECT terminal name
BYP ; scan past blanks
CALL FNDASN ; find and assign user supplied terminal-name
BNE EXEUNT ; no match
ORW #FIL!LOK,-10(A0) ; set file and locked in memo flags
20$: JOBIDX ; index A6 to JCB
ANDW #^C<J.CCC>,@A6 ; clear control-c
CALL CHOICE ; get user's command choice
BNE 20$ ; no such command!
CALL PROCES ; perform user's command
TSTB DONE(A0) ; done ?
BEQ 20$ ; no, accept another command.
40$: CLRB DONE(A0)
; E X E U N T - exit back to AMOS
EXEUNT: EXIT
; I N I M E M
; This routine builds, clears and initializes the user's impure area.
INIMEM: LEA A6,IMPNAM ; index impure module name
SRCH @A6,A0,F.USR ; search user area for kermit
BEQ 10$ ; already present-done
GETIMP KSIZE,A0,100$ ; allocate impure area
CLEAR @A0,KSIZE ; clear it (redundant now, so what!)
LEA A6,IMPNAM
MOV (A6)+,-6(A0) ; set module name to program name
MOVW @A6,-2(A0) ; set module extension to .IMP
; do first time-only inits
CALL INI2 ; get JCB & attached TCB addresses
CALL INIXFR ; init xfer section once.
CALL OSVER ; determine O/S version
CALL TRMVER ; determine terminal driver version
MOVB #ESCCHR,KMETA(A0) ; set CONNECT ESCAPE character
MOVB #PAKSIZ,MXPKSZ(A0) ; set maximum packet size allowed [13]
MOV #100.,SLPVAL(A0) ; set sleep ticks for GETREM [14]
MOVB #-1,AUTOS(A0) ; invoke auto-send [15]
MOVB #-1,AUTOR(A0) ; invoke auto-receive [16]
LCC #PS.Z
RTN
; finish re-entry inits
10$: CALL INI2 ; get JCB & attached TCB AGAIN
BYP ; [024]
LIN ; [024] port named?
BEQ 20$ ; [024] no
TTYL RENTER ; [024] yes, been there, done that!
20$: LCC #PS.N!PS.Z ; set N and Z if impure already there
RTN
; not enough memory, so depart
100$: TYPECR <?Insufficient memory for KERMIT.>
LCC #0 ; flag no memory
RTN
; OSVER plays twenty questions games to find out what resources are
; available in current operating system.
OSVER: MOV SYSTEM,D7
AND #SY$EXD,D7 ; system supports extended disks?
SETNE EXTEND(A0) ; set flag -1 if extended disk O.K.
CLRB COMSER(A0) ; assume we don't have new comm stuff
MOV SYSTEM,D7 ; get system word
AND #SY$M20!SY$M30!SY$M40,D7 ; mask to just AMOS/32
BNE 10$ ; all AMOS/32 has COMSER, CMDLIN
CMPB PH.VER+.B8W15,#1. ; MAJOR higher than 1?
BHI 10$ ; yes-use new value
MOVB PH.VER+.B16L23,D7 ; no- get sub release
ANDB #^O17,D7 ; strip out VWHO in top 4 bits
CMPB D7,#3. ; is this 1.3?
BLO 30$ ; no-1.2 or older, no COMSER
BHI 10$ ; no-1.4 or higher COMSER fur sure!
SETB WILDOK(A0) ; wildcarding started in 1.3
MOVB PH.VER+.B8L15,D7 ; exactly 1.3 - check for B
LSRB D7,#4. ; bring it to ground zero.
CMPB D7,#'I-'@ ; is it B or higher?
BEQ 30$ ; 1.3I comes before 1.3B (go figure)
CMPB D7,#'B-'@ ; is it B or higher?
BLO 30$ ; yes-use new value
10$: SETB WILDOK(A0) ; O.K. to user CMDLIN.SYS
20$: SETB COMSER(A0) ; O/S has COMSER routines
30$: RTN ; O/S has got not a lot...
; determine terminal driver resources (7 or 8 bit system & terminal driver)
TRMVER: MOVB #^B01111111,CMASK(A0) ; preset mask for 7 bit terminal
MOV SYSTEM,D7 ; get system type
AND #SY$EXT,D7 ; does system support 8 bit terms?
BEQ 10$ ; no
MOV LOCAL(A0),A5 ; A5 indexs local TCB
MOV T.TDV(A5),A6 ; index terminal driver
MOVW TD.TYP(A6),D7 ; get type word
ANDW #TD$NEW,D7 ; is it a "new" TDV
BEQ 10$ ; no, use 7 bit mask
MOV TD.FLG(A6),D7 ; yes, get tdv's flag bits
AND #TD$EXT,D7 ; mask
BEQ 10$ ; tdv is recent, but only 7 bit!
MOVB #-1,CMASK(A0) ; TDV supports 8 bit terminals
10$: RTN
; These values are inited every time KERMIT is executed.
INI2: JOBIDX A6 ; index A6 to JCB
MOV JOBTRM(A6),LOCAL(A0) ; save address of local TCB
RTN
; I N I X F R
; Initialize the the file transfer area
INIXFR: MOVB #MYEOL,DF.EOL(A0) ; set default EOL [17]
MOVB #MYCHK,DF.CHK(A0) ; set default check type
MOVB #'N,PARITY(A0) ; set parity to NONE.
MOVB #PAKSIZ,SPSIZ(A0) ; set max send size
;
MOVB #SOH,RMARK(A0) ; define start of packet byte
MOVB #MYQUOT,QUOTE(A0) ; set quote char
MOV LOCAL(A0),A5 ; set index
MOVB #MYPAD,PAD(A0) ; pad count
MOVB #MYPCHR,PADCHR(A0) ; & character
MOVB #TRIES,MAXTRY(A0) ; set max tries
MOVB #'1,CHKT(A0) ; checkbyte type
MOV #08.,TIMINT(A0) ; set timeout period
MOV #08.,DF.TIM(A0) ; set default timeout period
RTN
; F N D A S N
; FNDASN finds the user specified TCB, and marks it as busy if found.
; The "busy" bit in the TCB depends on the O/S version.
; If the O/S version is before 1.3B AMOS/L, the busy bit is bit 11. of T.STS
; If the O/S is AMOS/32, or AMOS/L 1.3B or later, the busy is bit 9. of T.STS
FNDASN: JOBIDX A6 ; index A6 to JCB
MOV JOBTRM(A6),A5 ; index our own TCB as default
LIN ; user provide terminal name
BEQ 25$ ; no-use our own terminal
LEA A1,TNAME(A0) ; index terminal name storage
PUSH A1 ; save for unpack
PACK
PACK ; pack the terminal name RAD50
POP A1
LEA A2,ATERM(A0) ; then unpack it for later
UNPACK
UNPACK
CLRB @A2 ; save ASCII version for SHOW.
MOV TNAME(A0),D6 ; D6 gets whole RAD50 terminal name
LEA A3,TRMDFC ; index the head of the TCB chain
10$: MOV @A3,D7 ; get link to next entry
JEQ 100$ ; no matching TCB name [010]
MOV D7,A3 ; A3 indexs next element
20$: CMPL D6,4(A3) ; compare to this entry
BNE 10$ ; try next one if no match
; TCB with matching name is found. Check for prior use
LEA A6,10(A3) ; index A6 to remote TCB [010]
CMP A5,A6 ; using specified own terminal? [010]
BNE 22$ ; no
CLRB ATERM(A0) ; yes-clear name of terminal to [010]
; to flag comm port & user's [010]
; port are the same. [010]
22$: MOV A6,A5 ; index A5 to comm port [010]
25$: MOVW @A5,SAVSTS(A0) ; save the TCB status
CALL INUSE ; get proper in-use bits
TSTB ATERM(A0) ; user & comm port the same? [010]
BEQ 250$ ; yes-leave busy bit as is [010]
BSET D6,1(A5) ; set "assigned" bit
BNE 110$ ; already set by prior use-.
250$: MOV A5,REMOTE(A0) ; save pointer to remote TCB [010]
MOV T.TDV(A5),SAVTDV(A0) ; save old TDV address
; find address of PSEUDO TCB in memory for data transfer use.
MOV SAVTDV(A0),PSEUDO(A0) ; preset any TDV in case PSEUDO is gone!
MOV TRMTDC,A6 ; get base of tdv chain
MOV #[PSE]_16.+[UDO],D7 ; D7 gets PSEUDO in RAD50 notation
30$: CMP D7,4(A6) ; match ?
BEQ 40$ ; yes
MOV @A6,A6 ; no-get next link
MOV A6,D6 ; set flags
BNE 30$ ; keep trying
BR 50$ ; give up
40$: ADD #^O10,A6 ; add offset size of link word and name
MOV A6,PSEUDO(A0) ; save address of PSEUDO driver
50$: CMP A5,LOCAL(A0) ; TCB same as job's terminal's?
SETEQ NOTALK(A0) ; yes-flag KERMIT owns the data TCB
BEQ 60$ ; and bypass TDV swap.
; swap in PSEUDO terminal driver instead of normal TDV because some TDVs will
; use multi-byte capture sequences or other translate routines, which will
; mess up incoming or outgoing data.
; (There is a cleaner way to do this in newer O/Ss, but it isn't
; backwards compatible, so we won't bother - rpr 12/31/91)
MOV PSEUDO(A0),T.TDV(A5) ; substitute PSEUDO driver on remote
; unless TCB is owned by KERMIT job, detach all TCB <=> JCB links
60$: MOV T.JLK(A5),A6 ; get JCB link
MOV A6,SAVJCB(A0) ; save the JCB address for EXIT
BEQ 70$ ; TCB already detached-done
TSTB NOTALK(A0) ; TCB owned by KERMIT job?
BNE 70$ ; yes-leave it attached
CLR JOBTRM(A6) ; else detach TCB from job
CLR T.JLK(A5) ; and job from TCB
70$: LCC #PS.Z
RTN
100$: TTYL NMTN
LCC #0
RTN
110$: TYPECR <?terminal is being used by another job.>
LCC #0
RTN
; INUSE - routine to determine the proper INUSE bit values for this OS.
; The "busy" bit in the TCB depends on the O/S version.
; If the O/S version is before 1.3B AMOS/L, the busy bit is bit 11. of T.STS
; If the O/S is AMOS/32, or AMOS/L 1.3B or later, the busy is bit 9. of T.STS
; delivers status bit value for BTST to D6
INUSE:
MOV #1+8.,D6 ; D6 gets new INUSE bit value
TSTB COMSER(A0) ; do we have COMSER?
BNE 20$ ; yes
MOV #3.+8.,D6 ; set old INUSE bit
20$: RTN
; R A W T R M - set datacomm TCB to pass all data intact, character mode.
RAWTRM: MOV REMOTE(A0),A5 ; get index to the TCB
MOVW #REMMOD,D1 ; remote mode bits
CALL SETSTS ; set the status
RTN
; L I N T R M - set datacomm TCB for normal AMOSL line mode.
; except echo is supressed if same TCB for comm & commands
LINTRM: TSTB NOTALK(A0) ; same TCB for comm and job?
BEQ 10$ ; no-just return
; enable line input mode so user can enter commands
MOV REMOTE(A0),A5 ; yes-get index to the TCB
MOVW #^C<REMMOD>,D1 ; clear remote mode bits
CALL SETSTS ; clear the status
10$: RTN
; P S E T D V - assign PSEUDO driver if data TCB is owned by KERMIT job.
PSETDV: TSTB NOTALK(A0) ; TCB owned by KERMIT job?
BEQ 10$ ; no-no need to swap
MOV PSEUDO(A0),T.TDV(A5) ; swap in PSEUDO driver
10$: RTN
; O R G T D V - set normal terminal driver if data TCB is owned by KERMIT job.
ORGTDV: TSTB NOTALK(A0) ; TCB owned by KERMIT job?
BEQ 10$ ; no-no need to swap
MOV SAVTDV(A0),T.TDV(A5) ; swap back real terminal driver
10$: RTN
; S E T S L P - set SLEEP delay time based on serial baud rate
; added in edit [14]
SETSLP: MOV #100.,D6 ; set default value
CLR D7
MOVW T.BAU(A5),D7 ; get baud rate code
CMPW D7,#^O23 ; is it defined in our table?
BHI 10$ ; no, use default
LSLW D7 ; double index value
MOVW SLPTBL[D7],D7 ; get table value in D7
BEQ 10$
MOV D7,D6
10$: MOV D6,SLPVAL(A0) ; set sleep value
RTN
; sleep time in ticks for one character at all defined alpha baud rates
SLPTBL: WORD 100000./50.
WORD 100000./75.
WORD 100000./110.
WORD 100000./134.
WORD 100000./150.
WORD 100000./200.
WORD 100000./300.
WORD 100000./600.
WORD 100000./1200.
WORD 100000./1800.
WORD 100000./2000.
WORD 100000./2400.
WORD 100000./3600.
WORD 100000./4800.
WORD 100000./7200.
WORD 100000./9600.
WORD 100000./19200.
WORD 100000./38400.
WORD 100000./57600.
WORD 100000./76800.
; end [14] additions for SETSLP
; S N O O Z E - delay if data TCB owned by KERMIT job. This gives user
; time to escape back to the other KERMIT and enter REC.
SNOOZE: TSTB NOTALK(A0) ; data TCB same as KERMITs?
BEQ 10$ ; no - do not wait.
SLEEP #5.*10000. ; yes - wait 5 seconds
10$: RTN
; E V L C H R
; EVLCHR evaluates the next non-blank character indexed by A2 and
; returns its value in D1.
; At exit, A2 is updated, and D1 contains the new character or 0.
; The Z flag is set if a character was encountered, else Z is clear.
EVLCHR: CLR D1 ; pre-clear
BYP
LIN ; end of line?
BEQ 100$ ; yes-no characters to process
NUM ; else check for numeric
BNE 10$ ; not numeric
GTDEC ; get the value
BR 40$ ; and use it
; process non-numeric
10$: MOVB (A2)+,D1
CMPB D1,#'^ ; control character prefix ?
BNE 20$ ; no-use straight ASCII.
LIN ; yes-check again for end of line
BEQ 40$ ; treat as the ^ character [21]
MOVB (A2)+,D1 ; else get next character
AND #^O37,D1 ; mask to control character
BR 40$ ; and exit
20$: CMPB D1,#SPACE ; compare to ASCII space
BLO 100$ ; invalid argument
LIN
BNE 100$ ; bad input, too many chars
40$: LCC #PS.Z ; arg ok, value in D1
RTN
100$: LCC #0 ; arg is bad.
RTN
; P R O M P T displays the KERMIT command prompt.
PROMPT:
MOV #CR,D1
TTY
TSTB ATERM(A0) ; is this kermit the REMOTE?
BNE 10$ ; no
TYPE <REMOTE > ; yes-give user different prompts
10$: TTYI ; for local & remote kermies.
ASCII /Alpha-Kermit >/
BYTE 0
EVEN
RTN
; C H O I C E - prompts the user for command & gets the command.
CHOICE: CALL PROMPT ; prompt the user
KBD 25$ ; get a command line in line mode
BYP ; scan past blanks
LIN ; end of line?
BEQ CHOICE ; ignore blank lines
LEA A1,KERCOM ; index argument list
CALL COMAND ; match the command
BEQ 30$ ; command matched
; no match - show user bad news.
TYPE<? >
10$: LIN
BEQ 20$ ; end of line.
MOVB (A2)+,D1 ; else
TTY ; type the
BR 10$ ; character and loop
20$: TYPECR <? - undefined command.>; end error display
25$: LCC #0 ; flag no command
RTN ; return
30$: LCC #PS.Z ; flag valid command
RTN ; return
; C O M A N D - This subroutine compares the user's command string
; to the command list indexed by A1 (e.g. KERCOM).
; If a match is found, A1 will index the command offset for a tabled call.
; At entry, A1 indexs the command/subcommand list. A2 indexs user's string.
; At exit, Z is set to indicate the command was valid.
; If Z is set, A1 indexs the command offset word.
;
; This routine will match the entire command, or to a valid and unique subset
; of the command name as defined in the table structure.
; e.g. The string CON will match the command name CONNECT.
COMAND: SUB #2,A1 ; adjustment for first entry
BYP ; scan past seperators
PUSH A2 ; save string address for compares
LIN ; end of line?
BEQ CHO.5 ; no command-exit.
; calculate address of next entry and place in A1.
CHO.1: MOV @SP,A2 ; restore string pointer
LEA A3,2(A1) ; A3 indexs next entry
TSTW @A3 ; end of table ?
BEQ CHO.5 ; yes-no match.
MOV A3,A1 ; no-get address of command size word
ADDW (A3)+,A1 ; and index to next command.
CLR D5
MOVB (A3)+,D5 ; D5 gets qualifier size in bytes
CHO.2: TRM ; check for end of word
BEQ CHO.4 ; yes-check match count
TSTB @A3 ; check for end of table entry
BEQ CHO.1 ; must be wrong if so.
CHO.3: MOVB @A2,D1
UCS ; convert to upper case
CMPB D1,(A3)+ ; compare strings
BNE CHO.4 ; until no match
ADD #1,A2 ; advance A2
TST D5 ; check for minimum match length
BEQ CHO.2 ; made it-stop counting
SUB #1,D5 ; decrement byte count
BR CHO.2 ; keep testing till line is terminated
CHO.4: TST D5 ; good match has zero count
BNE CHO.1 ; no good-try next
TRM ; good match has no more data
BNE CHO.1
POP ; toss old A2
LCC #PS.Z ; flag command match found
RTN
; undefined command - Clear Z flag
CHO.5: POP A2 ; update A2 to index args
LCC #0
RTN
; P R O C E S
; Process performs the process defined by the user command.
; At Entry, A1 indexs the word offset (from A1) of the command address
PROCES: ADDW @A1,A1 ; do a tabled called by adding
CALL @A1 ; offset @A1 to A1 and executing at
RTN ; that new address.
; S E N D sends a file to the remote KERMIT using the KERMIT protocol.
SEND: TSTB NOTALK(A0)
BNE 4$ ; AUTOsend doesn't make sense in REMOTE
TSTB AUTOS(A0) ; automatically sending KERMIT & RECEIVE?
BEQ 4$ ; no
TYPECR <Sending KERMIT and RECEIVE commands to remote Kermit>
LEA A1,PRESND ; index commands for remote kermit
CALL SREMOT ; send to remote
4$: CALL PREBAT ; init wildcarding, if present
BYP
5$: CALL GETNXT ; get next filename
; delay inspection of no files error until we are ready to send F packet,
; then, just send a B packet.
TSTB FIO+D.ERR(A0) ; file error?
BEQ 6$ ; no
CALL LFERR ; yes, display it
BR 5$ ; and try for another spec
6$: CALL GTSIZE ; save file size in bytes
CALL STARTT ; set start time
CALL RAWTRM ; put remote in data mode
CALL SNOOZE ; delay if TCB owned by KERMIT
CALL PSETDV ; swap in PSEUDO driver if needed
CALL SETSLP ; set sleep parameter
CALL SENDSW ; else send the file
CALL LINTRM ; put remote in line mode
CALL ORGTDV ; put back real TDV if PSEUDO used
TSTB LOGIC(A0) ; did it work?
BMI 10$ ; yes
TYPECR <?SEND failed> ; no
10$: CALL STATS
20$: RTN
100$: CALL LFERR
RTN
; L F E R R
; LFERR displays local file errors on the user's CRT
LFERR: TSTB NOTALK(A0) ; do we have a user terminal?
BNE 10$ ; no-do not print message.
TYPE <Local file error, >
PFILE FIO(A0) ; show filename
ERRMSG FIO+D.ERR(A0), OT$TRM!OT$LSP ; and error message
CRLF
10$: RTN
; R E C E I V - receive a file from remote KERMIT using the KERMIT protocol.
RECEIV:
MOV A2,SAVSPC(A0) ; save user's string ptr
MOVB #1,NXTCNT(A0) ; set count for output spec
CALL SCNSTR ; scan string for AUTO-receive
CLR TFILES(A0)
CLR TBYTES(A0)
CLR TTIME(A0) ; clear total stat amounts
MOV #60.,TIMINT(A0) ; 60 second timeout
CALL SETSLP ; set sleep parameter
CALL PSETDV ; swap in PSEUDO terminal driver
CALL RAWTRM ; remote TCB to character mode
CALL RECSW ; call receive state manager/switcher
CALL LINTRM ; remote TCB to line mode
CALL ORGTDV ; return to real TDV if PSEUDO used
TSTB LOGIC(A0) ; test for sucess
BMI 10$ ; it worked
TYPECR <?RECEIVE failed.> ; it didn't work
10$: CALL STATS ; show elapsed time & speed
RTN
; scan user spec for = and spec following it. If found, send remote Kermit
; the commands KERMIT^M, and SEND followed by the user's filespec.
SCNSTR:
SAVE A2
TSTB NOTALK(A0)
BNE 100$ ; AUTOREC doesn't make sense in REMOTE
TSTB AUTOR(A0) ; automatically sending KERMIT & SEND?
BEQ 100$ ; no
BYP
LIN ; any parms?
BEQ 100$ ; no
CMPB @A2,#'= ; do we have an equal sign?
BEQ 20$ ; yes
FSPEC FIO(A0),LST ; no, use FSPEC to skip past outspec
BYP
20$: CMPB (A2)+,#'= ; do we have AUTO spec?
BNE 100$ ; no
; yes
TYPECR <Sending KERMIT and SEND commands to remote Kermit>
LEA A1,PREREC ; index commands for remote kermit
CALL SREMOT ; send to remote
MOV A2,A1
CALL SREMOT ; send user string ( even CR & LF)
100$: REST A2
RTN
; G F I L N M
; This routine gets a filename and places it in FILNAM(A0)
; At entry, the filename has been loaded in ddb FIO(A0)
; On exit, FLLEN(A0) contains the length in bytes.
; Z is set if the filename was valid.
GFILNM:
; now convert the name to KERMIT standard form which is NAME.EXT.
; We must delete all spaces from the filespec.
LEA A2,FILNAM(A0) ; index the target area
PUSH A2 ; and save the index
LEA A1,FIO+D.FIL(A0) ; index the filname in the ddb
UNPACK
UNPACK ; put the ASCII filename @A1
MOVB #'.,(A2)+ ; add the comma
UNPACK
CLRB @A2 ; terminate it
; clean up the filespec by deleting space & other illegal characters.
POP A2 ; restore pointer to filnam
MOV A2,A1 ; A1 will be write pointer
CLR D0 ; D0 counts valid chars we found
10$: MOVB @A2,D1 ; get current char in D7
BEQ 20$ ; end of line
LCS ; convert to lower case [15]
CMPB D1,#'. ; current char a dot?
BEQ 20$ ; yes -it is ok
ALF ; is it alpha ?
BEQ 20$ ; yes-use it.
NUM ; or numeric ?
BNE 25$ ; yes-use it
20$: MOVB D1,(A1)+
BEQ 30$ ; end of string
ADD #1,D0 ; count how many we found
25$: ADD #1,A2 ; bump pointer
BR 10$ ; continue scan
30$: CMP D0,#3 ; got at least x.x?
BLO 100$ ; no-invalid filename
MOVB D0,FLLEN(A0) ; save the length
LCC #PS.Z ; valid filename received
RTN
100$: LCC #0 ; bad filename given.
RTN
; R F I L N M
; This routine gets the remote filename from NFILNM(A0)
; and places it in the FIO(A0) DDB.
; It then opens the file for input and returns the OPEN condition codes
; to the caller. Z is set if the open was succesful.
; [13] revised to not extend filenames or extensions rpr
RFILNM:
LEA A2,FILNAM(A0) ; index the filname
LEA A1,COPY(A0) ; index copy buffer
CLR D2
MOVB LDATA(A0),D2 ; d2 gets total length of filename
; from remote kermit
CMP D2,#30.-1 ; compare to max allowed by definition
BLOS 10$
MOV #30.-1,D2 ; set max
; terminate filename part to 6 characters
10$: MOV #6.,D0 ; set limit for filename
20$: ALF
BEQ 30$ ; letters ok
NUM
BEQ 30$ ; numbers ok, too.
CMPB @A2,#'. ; period?
BEQ 60$ ; yes-end of filename!
BNE 40$ ; no-toss bad char & continue
30$: MOVB @A2,(A1)+ ; save good character
40$: ADD #1,A2 ; advance pointer
SUB #1,D2 ; count down total filename size
BEQ 100$ ; end of filename (use .KMT extension)
SUB #1,D0 ; adjust allowed filename chars
BNE 20$ ; more allowed
; else wait for a period.
; truncate file names longer than 6 characters by waiting for a period
; wait for a period
50$: CMPB @A2,#'. ; period
BEQ 60$ ; yes-ok.
ADD #1,A2 ; no-advance ptr
SUB #1,D2 ; count down total filename size
BNE 50$ ; until period or end of file
BR 100$ ; no period found
; we found the period (and truncated a long filename)
60$: ADD #1,A2 ; no-advance
SUB #1,D2 ; count down original filename size
BEQ 100$ ; no more filename, use default ext!
MOVB #'.,(A1)+ ; buffer a period
MOV #3.,D0 ; max size of extension.
70$: ALF
BEQ 80$ ; ok
NUM
BNE 90$ ; not ok
80$: MOVB @A2,(A1)+ ; buffer o.k. character
90$: ADD #1,A2 ; advance pointer
SUB #1,D2 ; count down original filename size
BEQ 100$ ; until a period
SUB #1,D0 ; count down
BNE 70$ ; yes
100$: CLRB (A1)+ ; no- end with a null
; add code to override the name of first file received, if user gave a name
TSTB NXTCNT(A0) ; been here before?
BEQ 106$ ; yes, not first time
MOV SAVSPC(A0),A2 ; no, get user spec
BYP
LIN ; do we have text?
BEQ 106$ ; no, user name from F packet
CMPB @A2,#'= ; yes, is text a filename?
BNE 107$ ; yes, override filename!
INC A2 ; else use name from F packet
BYP
106$: CLRB NXTCNT(A0)
LEA A2,COPY(A0) ; index the new filename
107$: INIT FIO(A0) ; init the ddb
FSPEC FIO(A0),KMT ; load the ddb with filespec
LOOKUP FIO(A0) ; does file already exist?
BNE 110$ ; no
DSKDEL FIO(A0) ; yes-erase the old one
110$: OPENO FIO(A0) ; open it sequentially
BNE 120$
CALL STARTT ; start counting
CLR D7 ; clear Z flag
120$: RTN ; Z is set if file found
; C O N N E C
; CONNEC is the local terminal <--> remote terminal conversational routine.
; User keypresses are sent (except the ESCAPE or KMETA character) to the
; remote computer & incoming characters form the remote are displayed on
; the user's CRT screen.
CONNEC: TSTB NOTALK(A0) ; using same TCB for in & out?
BEQ 4$ ; no-ok.
TTYL NONONO ; tell user it is a no-no
RTN
4$: TAS CFLAG(A0) ; have we been here before?
BNE 5$ ; yes
TTYL CUSAGE ; no, explain CONNECT to user
5$: CALL RAWTRM ; set remote in "raw" mode.
CALL SETSLP ; set sleep parameter
CALL SHOESC ; show the escape character in effect.
MOV LOCAL(A0),A5 ; A5 indexs local TCB
MOVW #REMMOD,D1 ; allow function key xlation
TSTB CMASK(A0)
BPL 6$ ; 7 bit terminal
ORW #T$EXT,D1 ; 8 bit terminal
6$: CALL SETSTS ; set them via breakpoint
MOV A5,A4 ; A4 will be the local TCB pointer
MOV REMOTE(A0),A5 ; now A5 indexs REMOTE
10$: CTRLC 15$ ; user entered control-c?
TST T.ICC(A4) ; LOCAL chars present ?
BNE 20$ ; something to do
TST T.ICC(A5) ; REMOTE chars present ?
BNE 20$ ; something to do
SLEEP SLPVAL(A0) ; take a one character nap. [14]
BR 10$ ; see if the store needs minding now.
; handle control-c's by trapping them, unflagging them and sending them out.
15$: JOBIDX ; index A6 to JCB
ANDW #^C<J.CCC>,@A6 ; clear control-c flag
MOV #3,D1 ; get ASCII equivalent
BR 37$ ; send it out
; enter here when we have some communications data to move
20$: TST T.ICC(A5) ; have remote input ?
BEQ 30$ ; no
TTYIN ; yes-grab a character
CMPB PARITY(A0),#'N
BEQ 25$
ANDB #^B01111111,D1 ; strip to seven if PARITY is on [22]
25$: TTY ; print it
30$: TCKI ; have LOCAL input ?
BNE 40$ ; no local input
KBD ; yes-get local input via KBD
35$: MOVB D1,D7
ANDB CMASK(A0),D7 ; mask character to 7 or 8 bits
CMPB D7,KMETA(A0) ; escape character ?
BEQ 100$ ; yes-leave
; check for half duplex echoing
TSTB ECHO(A0) ; got echoing?
BEQ 37$ ; no-full duplex
CMPB D7,#SPACE ; printable?
BHIS 36$ ; yes-echo it
CMPB D7,#CR ; CR?
BEQ 36$ ; yes-echo
CMPB D7,#08. ; backspace?
BEQ 36$ ; yes-echo
CMPB D7,#12 ; line feed ?
BNE 37$ ; ignore other ctl chars
36$: TTY ; yes-half duplex,
; so echo the character
; transmit a character to the remote site.
37$: TTYOUT ; send byte to REMOTE
40$: BR 10$ ; loop
; exit back to main routine, since user entered ESCAPE character.
100$: MOV LOCAL(A0),A5 ; index user's TCB
MOVW #REMMOD,D1 ; get char mode bits
TSTB CMASK(A0)
BPL 110$ ; 7 bit terminal
ORW #T$EXT,D1 ; 8 bit terminal
110$: COMW D1 ; flip the bits to clear
CALL SETSTS ; clear them via breakpoint
;; CALL LINTRM ; reset remote TCB to line mode.
CRLF
RTN
; H E L P - inform user as to how KERMIT works.
HELP: TTYL HLP1
LEA A1,KERCOM ; index argument list
CALL COMAND ; see if we have an argument
BNE 100$ ; no-show the whole list.
; show the selected help line by backing up to the start of it
4$: TSTB -(A1) ; backup to non-null
BEQ 4$
10$: MOVB -(A1),D1 ; look for null byte between command
BNE 10$ ; and help strings.
CRLF
TTYL 1(A1) ; show the help message
CRLF
RTN
; Show help lines for all commands
100$: LEA A2,KERCOM ; index table
110$: MOV A2,A1
CLR D7
MOVW @A1,D7 ; get offset to end
BEQ 140$ ; null is end of table
MOV A1,A2
ADDW (A1)+,A2 ; A2 indexs the address field
ADD #2,A2 ; A2 now indexs the next entry
ADD #1,A1 ; ignore size byte
CLR D0
CALL PTRTYP ; type command name
TSTB @A1
BNE 120$
ADD #1,A1
120$: CMPB D0,#09. ; nine characters?
BHI 130$ ; yes, done spacing
INC D0 ; no,
TYPESP ; so space
BR 120$ ; out
130$: CALL PTRTYP ; type the help text
CRLF
BR 110$
140$: CRLF
CRLF
RTN
; S H O W - Show user the current optional settings & some packet info.
SHOW: CALL KERVER ; show kermit version
TTYL SH1.0 ; type modem port:
LEA A1,ATERM(A0) ; index TCB name
TSTB @A1 ; do we have remote? [1]
BNE 10$ ; yes
LEA A1,SH.DAS ; else index dashes
10$: TTYL @A1 ; show name or dashes
; [016] display auto-receive
TTYL SH2.0
LEA A6,SH.ON
TSTB AUTOR(A0)
BNE 20$
LEA A6,SH.OFF
20$: TTYL
; [015] display auto-send
TTYL SH2.1
LEA A6,SH.ON
TSTB AUTOS(A0)
BNE 30$
LEA A6,SH.OFF
30$: TTYL
; display bell
TTYL SH2.2 ; do end of line 1 & BELL label
LEA A6,SH.OFF
TSTB DING(A0)
BEQ 40$
LEA A6,SH.ON
40$: TTYL ; show on or off
; display blockcheck
TTYL SH2.3 ; blockcheck selected label
MOVB DF.CHK(A0),D1
TTY
; display debug
TTYL SH2.4 ; show DEBUG label
LEA A6,SH.OFF
TSTB DEBUGO(A0)
BEQ 50$
LEA A6,SH.ON
50$: TTYL
; show duplex
TTYL SH2.5 ; then type duplex label
LEA A6,SH.FUL ; assume FULL
TSTB ECHO(A0) ; check duplex 0=full, -1=half
BEQ 60$
LEA A6,SH.HAL ; o.k., then, HALF.
60$: TTYL ; type string @A6
; display user's endline
TTYL SH3.2 ; end of line 3, ENDLINE label
;[012] display end-of-line character in use, rather than default
MOVB DF.EOL(A0),D1 ; set end of line char
BNE 65$
TTYL SH.ZIP
BR 67$ ; [015]
65$: TYPE < >
CALL SHOCHR
67$:
; display ESCAPE
TTYL SH2.6 ; show ESCAPE label
CLR D1 ; preclear D1
MOVB KMETA(A0),D1
CALL SHOCHR ; show escape character
; display PACKETSIZE
TTYL SH2.7
CLR D1
MOVB MXPKSZ(A0),D1 ; set max value
DCVT 4,OT$TRM!OT$ZER
; display PACKETSTART
TTYL SH2.7A
MOVB RMARK(A0),D1
CALL SHOCHR
; display PARITY
TTYL SH2.8 ; type parity label
MOVB PARITY(A0),D1
CALL SHOCHR
; display default retries
TTYL SH2.8A
MOVB MAXTRY(A0),D1
DCVT 4,OT$TRM!OT$ZER
; display stall time in hundredths of seconds
TTYL SH2.9
CLR D1
MOVB STLCHR(A0),D1
DCVT 4,OT$TRM!OT$ZER
; display default TIMOUT
TTYL SH2.9A ; show timeout label
MOV DF.TIM(A0),D1 ;
DCVT 4,OT$TRM!OT$ZER
CRLF
; display packet parameters
; display blockchek
TTYL SH3.0
MOVB CHKT(A0),D1 ; get check type
TTY
; display eight bit quote
TTYL SH3.1
MOVB QBIN(A0),D1
BMI 70$ ; 7 bit path
BNE 80$ ; we have a real 8B quote, show it
TTYL SH.ZIP ; we don't need 8B quote so far
BR 90$
70$: MOVB #'&,D1 ; show default 8 bit quote
80$: TYPE < >
CALL SHOCHR
90$:
; display endline
TTYL SH3.2 ; end of line 3, ENDLINE label
;[012] display end-of-line character in use, rather than default
MOVB DF.EOL(A0),D1 ; set end of line char
BNE 100$
TTYL SH.ZIP
BR 110$ ; [015]
100$: TYPE < >
CALL SHOCHR
; display max packet size
110$: TTYL SH3.3 ; do end of line 2, packet parms.
CLR D1
MOVB SPSIZ(A0),D1 ; get packet size
DCVT 4,OT$TRM!OT$ZER
; display packet end
TTYL SH3.4 ; show number of pads
MOVB PAD(A0),D1 ;
DCVT 2,OT$TRM!OT$ZER
TTYL SH3.5 ; show pad character value
MOVB PADCHR(A0),D1 ;
CALL SHOCHR
TTYL SH3.6 ; show timout label
MOV TIMINT(A0),D1 ;
DCVT 4,OT$TRM!OT$ZER
TTYL SH3.8
RTN
; S E T - allow user to change some parameters.
; SET command accepts a sub-command (or argument) to define the action.
; If no sub-command is given, a short expansion of the subcommands is given.
SET: BYP
LIN ; end of line?
BEQ 100$ ; yes-show user what can be set.
CMPB @A2,#'? ; user wants some help?
BEQ 100$ ; yes-show user what he can set.
LEA A1,SETCOM ; index set command list
CALL COMAND ; see if we have an argument
BNE 10$ ; no-show user no can do.
; perform the desired function. Each function does its own error-checking.
CALL PROCES ; do the set
RTN
10$: TYPE<? > ; no match - show user bad news.
15$: LIN ; end of line?
BEQ 20$ ; yes-done typing user's entry
MOVB (A2)+,D1
TTY ; type a character
BR 15$ ; until the end of line
20$: TYPECR <? - undefined command.>
25$: RTN
; Show explanation for all set commands
100$: TTYL SET1
LEA A2,SETCOM ; index table
110$: MOV A2,A1
CLR D7
MOVW @A1,D7 ; get offset to end
BEQ 140$ ; null is end of table
MOV A1,A2
ADDW (A1)+,A2 ; A2 indexs the address field
ADD #2,A2 ; A2 now indexs the next entry
ADD #1,A1 ; ignore size byte
CLR D0 ; [015] count characters
CALL PTRTYP ; type command name
TSTB @A1
BNE 120$
ADD #1,A1
120$: CMPB D0,#11. ; eleven characters?
BHI 130$ ; yes, done spacing
INC D0 ; no,
TYPESP ; so space
BR 120$ ; out
130$: CALL PTRTYP ; type the help text
CRLF
BR 110$
140$: CRLF
CRLF
RTN
;; S E T S U B C O M M A N D S
; B E L L - set bell after each command completeion flag.
BELL: LEA A1,ONOFF ; index option list
CALL GETOPT ; process option
BNE 10$ ; no good
MOVB D1,DING(A0) ; set bell option
10$: RTN
; D U P L E X - set half or full duplex.
DUPLEX: LEA A1,EPLEX ; index echoplex options
CALL GETOPT ; process option
BNE 10$ ; no good
MOVB D1,ECHO(A0) ; set duplex option
10$: RTN
; B L O C K - set default check type. 1, 2 or 3 byte check types
BLOCK: LEA A1,ONE23 ; index check-type options
CALL GETOPT
BNE 10$ ; no good
MOVB D1,DF.CHK(A0) ; set default check type
10$: RTN
; D E B U G - Set debug message print flag.
DEBUG: LEA A1,ONOFF ; allow YES or NO.
CALL GETOPT
BNE 10$
MOVB D1,DEBUGO(A0) ; set debug option
10$: RTN
; A U T S N D - Set AUTOSEND option flag.
AUTSND: LEA A1,ONOFF ; allow YES or NO.
CALL GETOPT
BNE 10$
MOVB D1,AUTOS(A0) ; set autosend option
10$: RTN
; A U T R E C - Set AUTORECEIVE option flag.
AUTREC: LEA A1,ONOFF ; allow YES or NO.
CALL GETOPT
BNE 10$
MOVB D1,AUTOR(A0) ; set autosend option
10$: RTN
; E N D L I N - set optional end of packet character. (normally CR.)
ENDLIN: CALL EVLCHR ; get the character
BNE 10$
MOVB D1,DF.EOL(A0) ; set default EOL
10$: RTN
; P A K M R K - set optional start of packet character. (normally CR.)
PAKMRK: CALL EVLCHR ; get the character
BNE 10$
MOVB D1,RMARK(A0) ; set default MARK character
10$: RTN
; E S C A P E - set the escape from CONNECT mode character.
ESCAPE: CALL EVLCHR
BNE 10$ ; no good
ANDB CMASK(A0),D1 ; limit to valid character set range
MOVB D1,KMETA(A0) ; set escape character
10$: RTN
; T I M E R - set the timeout period used in packet transmission.
TIMER: BYP
GTDEC ; get decimal number
CMP D1,#MINTIM ; compare to minimum time
BHIS 10$ ; allow 2 or more
MOV #MINTIM,D1 ; force minimum
TYPECR <Setting timeout to 2 second minimum.>
10$: MOV D1,DF.TIM(A0) ; set default and
MOV D1,TIMINT(A0) ; current timer value
RTN
; N E W T R Y - sets the maximum # of tries for a packet.
NEWTRY: BYP
GTDEC
TST D1 ; test new value
BEQ 20$ ; zero is too few!
CMP D1,#255. ; this is max was ^O255
BHI 20$ ; too high-leave as is
MOVB D1,MAXTRY(A0) ; set max value
RTN
20$: TTYI
ASCII /?value out of range?/
BYTE A.BEL,CR,0
EVEN
RTN
; P A K M A X - set maximum packet size supported
PAKMAX: BYP
GTDEC
CMP D1,#10. ; compare to minimum
BLO 20$ ; too small [16]
CMP D1,#PAKSIZ ; compare to max size allowed
BHI 20$ ; too high-leave as is
MOVB D1,MXPKSZ(A0) ; set max value
MOVB D1,SPSIZ(A0) ; set max send size, too!
RTN
20$: TTYI
ASCII /?select a packet size from 10 to 94 bytes./
BYTE A.BEL,CR,0
EVEN
RTN
; S E T P A R - set the parity type (already in use) by the remote
; This allows Alpha-Kermit to know whether 8bit quoting is needed, or not.
SETPAR: LEA A1,PARLST ; allow YES or NO.
CALL GETOPT
BNE 10$
MOVB D1,PARITY(A0) ; set parity
CMPB D1,#'N ; no parity?
SETNE QBIN(A0)
TTYL NOSET ; tell user limitations
10$: RTN
; S T L V A L - set # of 100ths of seconds to stall between output
; characters for file transfers.
STLVAL: BYP
GTDEC
TST D1 ; test new value
BEQ 20$ ; zero is too few!
CMP D1,#255. ; this is max was ^O255
BHI 20$ ; too high-leave as is
MOVB D1,STLCHR(A0) ; set max value
RTN
20$: TTYI
ASCII /?STALL range is 0 to 255 hundredths of seconds./
BYTE A.BEL,CR,0
EVEN
RTN
; G E T O P T - compares the input option @A2 to the option list @A1.
; If there is a match, the match number is returned in D1 and Z is set.
; No match returns Z clear and displays the error message at the end of the
; option list.
GETOPT: SUB #2,A1 ; adjustment for first entry
BYP ; scan past seperators
PUSH A2 ; save string address for compares
; calculate address of next entry and place in A1.
OPT.1: MOV @SP,A2 ; restore string pointer
LEA A3,2(A1) ; A3 indexs next entry
TSTW @A3 ; end of table ?
BEQ OPT.5 ; yes-no match.
MOV A3,A1 ; no-get address of command size word
ADDW (A3)+,A1 ; and index to next command.
CLR D5
MOVB (A3)+,D5 ; D5 gets qualifier size in bytes
OPT.2: TRM ; check for end of word
BEQ OPT.4 ; yes-check match count
TSTB @A3 ; check for end of table entry
BEQ OPT.1 ; must be wrong if so.
OPT.3: MOVB @A2,D1
UCS ; convert to upper case
CMPB D1,(A3)+ ; compare strings
BNE OPT.4 ; until no match
ADD #1,A2 ; advance A2
TST D5 ; check for minimum match length
BEQ OPT.2 ; made it-stop counting
SUB #1,D5 ; decrement byte count
BR OPT.2 ; keep testing till line is terminated
OPT.4: TST D5 ; good match has zero count
BNE OPT.1 ; no good-try next
TRM ; good match has no more data
BNE OPT.1
POP ; toss old A2
CLR D1
MOVB @A1,D1 ; D1 gets argument value
LCC #PS.Z ; flag command match found
RTN
; undefined command - Clear Z flag
OPT.5: POP A2
TTYL 2(A3) ; display error message at end of list
CRLF ; [15]
LCC #0
RTN ; return with Z clear
; P T R T Y P - print the string indexed by A1 until a null is found.
PTRTYP: MOVB (A1)+,D1
BEQ 10$
INC D0 ; count characters
TTY
BR PTRTYP
10$: RTN
; G O O D B Y - exit from KERMIT to AMOS for good.
; re-attach comm TCB to its former JCB, if any.
GOODBY: ANDW #^C<FIL!LOK>,-10(A0) ; clear file and locked in mem flags
MOV REMOTE(A0),A5
MOV #^C<REMMOD>,D1 ; clear bits we set (except OIP)
CALL INUSE ; get in-use bit
TSTB ATERM(A0) ; user & comm port the same? [010]
BEQ 4$ ; yes-leave busy bit as is [010]
BCLR D6,D1 ; clear it for bit clear mask
4$: CALL SETSTS ; clear all those bits
CLR D1
MOVW SAVSTS(A0),D1 ; get saved status
AND #^CT$OIP,D1 ; less OIP bit which hangs output!
CALL SETSTS ; set the saved bits
MOV SAVJCB(A0),A6
MOV A6,T.JLK(A5) ; restore any attached job
BEQ 10$
MOV A5,JOBTRM(A6) ; and JCB, if there was one
10$: MOV SAVTDV(A0),T.TDV(A5) ; restore TDV
SAVE A0 ; [16] JRUN the newly reattached job,
; if it is waiting for OIP
MOV SAVJCB(A0),D7 ; get saved job
BEQ 20$ ; no saved job
MOV D7,A0
MOVW JOBSTS(A6),D7 ; get job status
ANDW #J.TOW,D7 ; was job waiting for output?
BEQ 20$ ; no
JRUN J.TOW ; yes
20$: REST A0
SETB DONE(A0) ; set the we are done flag
RTN
; A M O S - move to AMOS level temporarily.
AMOS: SETB DONE(A0) ; set the we are done flag
RTN
; S E T S T S
; This routine sets or clears status bits in D1.
; If D1 is minus, the bits are cleared. If they are +, the bits are set
; This routine is used to set and reset TRMSER status word bits without
; getting T$OIP fouled up and hanging the job's output.
SETSTS: SUPVR
; This routine runs in SUPVR mode
; Used to change TRMSER status bits.
; Made compatible with smart I/O cards by using new monitor calls if
; O/S is new enough for it.
SVLOK ; prevent interrupts
TSTB COMSER(A0) ; do we have COMSER? [015]
BEQ 8$ ; no, do it old way
TSTW D1 ; clear or set bits?
BMI 4$ ; clear bits
; new way to change T.STS word without violating T.SEM rules.
PUSHW D1
TRMRST D1,@A5 ; read status
ORW (SP)+,D1 ; stir in the new bits
TRMWST D1,@A5 ; write status
BR 20$
4$: PUSHW D1
TRMRST D1,@A5 ; read status
ANDW (SP)+,D1 ; pick out the icky bits
TRMWST D1,@A5 ; write status
BR 20$
; old way to change T.STS word
8$: TSTW D1 ; set or clear bits?
BMI 10$ ; clear is negative
ORW D1,@A5 ; set bits if + or 0.
BR 20$ ; done setting...
10$: ANDW D1,@A5 ; clear those bits
20$: LSTS #0 ; unlock CPU & return to user mode
RTN
;;; F I L E T R A N S F E R R O U T I N E S
; S E N D S W
; SENDSW is the state table switch for file transfers. It loops either
; until it finishes, or an error is encountered. The routines called
; by SENDSW change the automaton state.
SENDSW:
MOVB #'S,STATE(A0) ; start with SEND INIT
CLRB N(A0) ; clear the seq number
CLRB NUMTRY(A0) ; and the retry count
CLRB LOGIC(A0) ; CLEAR LOGIC
CLRB RIACK(A0) ; clear the I is ACKed flag
10$: TSTB LOGIC(A0) ; test logic flag
BNE 100$ ; we are done
CTRLC ABORT ; exit on control-C
TSTB DEBUGO(A0) ; debug on ?
BEQ 20$ ; no
TYPE <SENDSW state >
MOVB STATE(A0),D1
TTY
CRLF
CRLF
20$: LEA A6,SWSTAT-4 ; index the state table
MOVB STATE(A0),D7 ; D7 gets the current state
30$: ADD #4.,A6 ; pre-advance
MOVB @A6,D6
BEQ 100$ ; undefined state - so exit
CMPB D6,D7 ; matching state ?
BNE 30$ ; no
ADD #2.,A6 ; yes - advance to offset
ADDW @A6,A6 ; calc address of new routine
CALL @A6 ; execute it
BR 10$ ; loop till we exit
100$: RTN
ABORT: MOVB #'A,STATE(A0) ; flag it as bad.
MOVB #FALSE,LOGIC(A0)
CALL CLOSER
RTN
COMPLT: MOVB #TRUE,LOGIC(A0) ; flag complete o.k.
RTN
; S I N I T
; Send (I) Initiate Packet & receive REMOTEs reply
SINIT: ADDB #1,NUMTRY(A0) ; bump # of tries
CMMB NUMTRY(A0),MAXTRY(A0) ; beyond the max?
BLOS 20$
MOVB #'A,STATE(A0)
10$: RTN
20$: LEA A3,PACKET(A0) ; index the packet area
CALL SPAR ; load default data for S packet
CALL FLUSH ; flush pending input
MOVB DF.EOL(A0),EOL(A0) ; use default EOL
SPACK #'S,N(A0),#PARSIZ,PACKET(A0) ; send an S packet
; just in case host requires an EOL character, send the default EOL value.
MOVB #CR,D1 ; send universal EOL value
CALL OUTBYT ; output the EOL to get remote going
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,RECPKT(A0),D4 ; receive a packet
BNE 1000$ ; no packet received ; timeout
; or damaged packet
CMPB D4,#'N ; NAK, try again
JEQ 1000$ ; just return, leave state as is.
CMPB D4,#'Y ; ACK ?
BNE 30$ ; no ACK
CMPB D3,N(A0) ; yes-same # as I sent?
BNE 1000$ ; no-return, same state
; get other side's init info.
SETB RIACK(A0) ; flag we got ACK to I packet
LEA A3,RECPKT(A0) ; index work area
CALL RPAR ; load parameters from work area
CMPB QUOTE(A0),#SPACE ; check for space or null
BHI 32$
MOVB #MYQUOT,QUOTE(A0) ; reset to #
32$: CLRB NUMTRY(A0) ; clear retries
CALL BUMPP ; bump N mod 64.
MOVB #'F,STATE(A0) ; move to state F
JMP 1000$ ; done
30$: CMPB D4,#'E ; error packet received ?
BNE 40$ ; no
CALL PRTERR ; show error
; move to abort state on any undefined TYPEs
40$: MOVB #'A,STATE(A0) ; move to abort state.
1000$: RTN
; S F I L E sends the file header.
SFILE: TSTB FIO+D.ERR(A0) ; error on input file?
BNE 2$ ; yes, move to break state
MOV CMNEXT(A0),D7
AND #NX$END,D7 ; end of specs?
BEQ 4$ ; no
2$: MOVB #'B,STATE(A0) ; yes, send a break
RTN
4$: INCB NUMTRY(A0) ; bump the count
CMMB NUMTRY(A0),MAXTRY(A0) ; beyond the max?
BLOS 10$ ; no
MOVB #'A,STATE(A0) ; set state to abort
RTN
10$: CLR D2
MOVB FLLEN(A0),D2
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'F,N(A0),D2,NFILNM(A0) ; send the F packet
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,RECPKT(A0),D4 ; wait for reply
BNE 1000$ ; no reply
; compare received sequence # to expected #
CMPB D4,#'N ; NAK ?
BNE 30$ ; no NAK here
; check to see if NAK is for next block, which we will
; interpret as being an ACK for this block.
CALL NEXTN ; D1 gets NEXT packet #
CMPB D1,D3 ; NAK for next block ?
BNE 1000$ ; no-return with state unchanged
BR 35$ ; yes-treat as ACK for this block
30$: CMPB D4,#'Y ; ACK ?
BNE 40$ ; no
MOVB N(A0),D1 ; D1 gets current SEQ #
CMPB D3,D1 ; yes-is it expected SEQ?
BNE 1000$ ; no-return state unchanged
35$: CLRB NUMTRY(A0) ; yes-clear retries count
CALL BUMPP
LEA A3,PACKET(A0)
CALL BUFFIL ; fill a buffer @A3
MOVB #'D,STATE(A0) ; goto Data state
JMP 1000$
40$: CMPB D4,#'E ; Error packet received
BNE 50$
CALL PRTERR ; show the error
; if any other case, move to abort case
50$: MOVB #'A,STATE(A0) ; move to abort state
1000$: RTN
; S D A T A - sends a portion of file contents
SDATA: INCB NUMTRY(A0) ; bump try count
CMMB NUMTRY(A0),MAXTRY(A0) ; maxxed out ?
BLOS 10$ ; no
MOVB #'A,STATE(A0) ; yes-move to abort state
RTN
10$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'D,N(A0),BUFCNT(A0),PACKET(A0) ; send data packet
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,RECPKT(A0),D4 ; receive a packet
JNE 1000$ ; no data received
CMPB D4,#'N ; NAK ?
BNE 15$ ; no
CALL NEXTN ; D1 gets N
CMPB D1,D3 ; NAK for N+1?
BEQ 40$ ; yes-treat as lost ACK for N
JMP 1000$ ; else exit state unchanged
15$: CMPB D4,#'Y ; ACK ?
BNE 70$ ; no
CMPB D3,N(A0) ; right SEQ of ACK?
BNE 1000$ ; no-state unchanged
TSTB LDATA(A0) ; is data length zero?
BEQ 30$ ; yes
;test for graceful abort request from RECeiving Kermit.
MOVB RECPKT+DATA(A0),D7 ; no-get the byte
ANDB #^O177,D7 ; strip to ACSII
CMPB D7,#'Z ; is it abort batch?
BNE 20$ ; no
SETB ABORTB(A0) ; yes, set abort batch flag
BR 30$ ;
20$: CMPB D7,#'X ; is it abort file?
BNE 30$ ; yes
SETB ABORTF(A0)
30$: CALL SHODOT ; tell user we moved some data
40$: CALL BUMPP ; bump packet count
TSTB ABORTF(A0) ; abort file?
BNE 50$ ; yes
CLRB NUMTRY(A0) ; clear the try count
LEA A3,PACKET(A0) ; index the Packet
CALL BUFFIL ; get a buffer
TSTB BUFCNT(A0) ; any data to send ?
BNE 60$
50$: CALL CLOSER ; close file
MOVB #'Z,STATE(A0) ; move to Z state (end of file)
JMP 1000$
60$: MOVB #'D,STATE(A0) ; stay in D state
JMP 1000$
70$: CMPB D4,#'E ; Error packet ?
BNE 1000$
CALL PRTERR
MOVB #'A,STATE(A0) ; move to A state.
1000$: RTN
; S E O F - send the end of file packet.
SEOF: INCB NUMTRY(A0)
CMMB NUMTRY(A0),MAXTRY(A0)
BLOS 10$
MOVB #'A,STATE(A0)
RTN
10$: CLR D2 ; D2 is packet size
TSTB ABORTF(A0) ; aborting this file ( or batch)?
BEQ 20$ ; no
MOV #1,D2 ; yes, set size to 1 byte
MOVB #'D,PACKET+DATA(A0) ; flag "DISCARD" to remote
20$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Z,N(A0),D2,PACKET(A0) ; send a Z packet
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,RECPKT(A0),D4 ; get a reply
BNE 1000$ ;
CMPB D4,#'N ; NAK ?
BNE 30$
CALL NEXTN ; D1 gets next N mod 64.
CMPB D1,D3 ; NAK for SEQ+1?
BEQ 40$ ; yes-treat as ACK.
JMP 1000$ ; return as is
30$: CMPB D4,#'Y ; ACK ?
BNE 60$ ; no
CMPB D3,N(A0) ; matching SEQ #?
BNE 1000$ ; no-return as is
40$: CALL BUMPP ; bump the N value
CALL ENDTM ; display speed stats
CALL DINGEM ; [015]
TSTB ABORTB(A0) ; abort batch? [015]
BNE 50$ ; yes [015]
CALL GETNXT ; any more files?
BVS 50$ ; no
TSTB FIO+D.ERR(A0) ; file error?
BNE 50$ ; yes, end transfer
CALL GTSIZE ; calc file size
CALL STARTT ; set start time
MOVB #'F,STATE(A0) ; reset state for more files
; CLRB N(A0) ; clear the seq number
CLRB NUMTRY(A0) ; and the retry count
JMP 1000$
; we found the "free time" for multiple files in 1991!
50$: MOVB #'B,STATE(A0) ; goto Break state
JMP 1000$
60$: CMPB D4,#'E ; error packet ?
BNE 70$ ; no
CALL PRTERR ; yes-print erorrrr.
JMP 1000$
70$: MOVB #'A,STATE(A0) ; abort on undefined types
1000$: RTN
; S B R E A K - sends a break frame (no more files to send).
SBREAK: INCB NUMTRY(A0) ; bump the try count
CMMB NUMTRY(A0),MAXTRY(A0) ; maxxed out?
BLOS 10$ ; no
MOVB #'A,STATE(A0) ; yes-abort state
RTN
10$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'B,N(A0),#0,PACKET(A0) ; send a B packet
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,RECPKT(A0),D4 ; get a reply
BNE 1000$ ; no reply
CMPB D4,#'N ; NAK ?
BNE 20$
CALL NEXTN ; D1 gets next N mod 64.
CMPB D1,D3 ; NAK for SEQ+1?
BEQ 30$ ; yes-treat as ACK.
JMP 1000$ ; return as is
20$: CMPB D4,#'Y ; ACK ?
BNE 40$ ; no
CMPB D3,N(A0) ; matching SEQ #?
BNE 1000$ ; no-return as is
30$: CALL BUMPP ; bump the N value
MOVB #'C,STATE(A0) ; goto Complete state
JMP 1000$
40$: CMPB D4,#'E ; error packet ?
BNE 50$ ; no
CALL PRTERR ; yes-print erorrrr.
JMP 1000$
50$: MOVB #'A,STATE(A0) ; abort on undefined types
1000$: RTN
; R E C S W - is the state table switch for receiving files.
RECSW: MOVB #'R,STATE(A0) ; start with RECV INIT state
CLRB N(A0) ; clear the seq number
CLRB NUMTRY(A0) ; and the retry count
CLRB LOGIC(A0) ; clear logic
CLRB RIACK(A0) ; clear the I is ACKed flag
10$: TSTB LOGIC(A0) ; test logic flag
BNE 100$ ; we are done
CTRLC RABOR ; or user wants out
TSTB DEBUGO(A0) ; debug on ?
BEQ 20$ ; no
TYPE <RECSW state >
MOVB STATE(A0),D1
TTY
CRLF
20$: LEA A6,RCSTAT-4 ; index the state table
MOVB STATE(A0),D7 ; D7 gets the current state
30$: ADD #4.,A6 ; pre-advance
MOVB @A6,D6
BEQ 100$ ; undefined state - so exit
CMPB D6,D7 ; matching state ?
BNE 30$ ; no
ADD #2.,A6 ; yes - advance to offset
ADDW @A6,A6 ; calc address of new routine
CALL @A6 ; execute it
BR 10$ ; loop till we exit
100$: RTN
RABOR: MOVB #'A,STATE(A0) ; flag transfer as bad
MOVB #FALSE,LOGIC(A0)
RTN
RCOMP: MOVB #TRUE,LOGIC(A0) ; flag complete o.k.
RTN
; R I N I T - is the receive init routine
; Wait for the send-init packet from sending Kermit.
RINIT: ADDB #1,NUMTRY(A0) ; count the tries
CMMB NUMTRY(A0),MAXTRY(A0) ; beyond the max?
BLOS 20$
MOVB #'A,STATE(A0)
RTN
20$:
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,PACKET(A0),D4 ; receive a packet
BNE 50$ ; no packet received ; timeout
CMPB D4,#'S ; got an S packet ?
BNE 30$ ; no S packet
; get other side's init data
LEA A3,PACKET(A0) ; index data packet address
CALL RPAR ; get parameters
LEA A3,PACKET(A0) ; index data packet address
CALL SPAR ; send our parameters
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,N(A0),#PARSIZ,PACKET(A0); send ACK with reply
SETB RIACK(A0) ; flag ACK to I has been sent
MOVB NUMTRY(A0),OLDTRY(A0) ; save try count
CLRB NUMTRY(A0) ; clear count
CALL BUMPP ; bump packet #
MOVB #'F,STATE(A0) ; bump state
JMP 1000$ ; end
30$: CMPB D4,#'E ; error received ?
BNE 40$
CALL PRTERR ; display the error.
MOVB #'A,STATE(A0)
JMP 1000$ ; done
; all others default to A state
40$: MOVB #'A,STATE(A0) ; received junk-abort
JMP 1000$
; no packet received - send a NAK
50$: SPACK #'N,N(A0),#0,NFILNM(A0) ; send a NAK packet
; return without state change
1000$: RTN
; R F I L E - receive a file header frame with the filename.
RFILE: ADDB #1,NUMTRY(A0) ; count the tries
CMMB NUMTRY(A0),MAXTRY(A0) ; beyond the max?
BLOS 20$
MOVB #'A,STATE(A0)
RTN
20$:
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,NFILNM(A0),D4 ; receive a packet (expecting filename)
JNE 500$ ; no packet received ; timeout
CMPB D4,#'S ; got an S packet ?
BNE 50$ ; no
; SEND-INIT received, maybe ACK was lost.
CALL NEXTO ; D1 gets next OLDTRY value
CMPB D1,MAXTRY(A0) ; time to give up?
BLOS 30$ ; no
MOVB #'A,STATE(A0)
JMP 1000$ ; yes-goto abort state.
30$: MOVB N(A0),D1 ; D1 gets current packet #
CALL PREVP ; get previous packet #
CMPB D1,D3 ; previous packet ?
BNE 40$ ; no
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,D3,#PARSIZ,PACKET(A0) ; yes-ack again with SEND-INIT
CLRB NUMTRY(A0) ; clear retry count
JMP 1000$ ; stay in state.
40$: MOVB #'A,STATE(A0) ; goto abort
JMP 1000$ ; done
50$: CMPB D4,#'Z ; end of file?
BNE 80$ ; no
CALL NEXTO ; D1 gets next oldtry
CMPB D1,MAXTRY(A0) ; time to give up?
BLOS 60$ ; no
MOVB #'A,STATE(A0) ; yes-abort
JMP 1000$ ; done
60$: MOVB N(A0),D1 ; get N
CALL PREVP ; calc previous packet # to D1
CMPB D1,D3 ; same ?
BNE 70$ ; no
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,D3,#0,PACKET(A0) ; yes-ack Z from file before!
CLRB NUMTRY(A0) ; reset tries
JMP 1000$ ; done
70$: MOVB #'A,STATE(A0) ; goto ABORT otherwise.
JMP 1000$
80$: CMPB D4,#'F ; is it the blessed file header yet?
JNE 200$ ; no
CMPB D3,N(A0) ; yes-is the packet # correct?
BNE 70$ ; no-move to abort state.
CALL RFILNM ; process the filename & open.
BEQ 90$ ; it opened ok
CALL LFERR ; show local file error
MOVB #'A,STATE(A0) ; move to abort state
JMP 1000$ ; done
90$: TSTB NOTALK(A0) ; do we have a user terminal?
BNE 120$ ; no-bypass message
CRLF
TYPE <Receiving >
CLR D0
MOVB LDATA(A0),D0
LEA A1,FILNAM(A0)
BR 110$
100$: MOVB (A1)+,D1
TTY
110$: DBF D0,100$
TYPE < as >
PFILE FIO(A0)
CRLF
120$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,N(A0),#0,PACKET(A0) ; send ACK for the F packet
MOVB NUMTRY(A0),OLDTRY(A0) ; reset try counters
CLRB NUMTRY(A0)
CALL BUMPP ; get next packet #
MOVB #'D,STATE(A0) ; move to data state
JMP 1000$
200$: CMPB D4,#'B ; break ?
BNE 300$ ; no
CMPB D3,N(A0) ; yes-is packet # correct?
BNE 310$
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,N(A0),#0,PACKET(A0) ; send ACK for the B packet
MOVB #'C,STATE(A0) ; and move to Complete state
JMP 1000$ ; end
300$: CMPB D4,#'E ; error frame ?
BNE 400$ ; no
CALL PRTERR ; show it
310$: MOVB #'A,STATE(A0) ; move to abort
JMP 1000$
400$: MOVB #'A,STATE(A0) ; goto abort state
JMP 1000$
; didnt get a packet
500$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'N,N(A0),#0,PACKET(A0) ; send NAK
1000$: RTN
; R D A T A - receives the data packets that make up the file.
RDATA: ADDB #1,NUMTRY(A0) ; count the tries
CMMB NUMTRY(A0),MAXTRY(A0) ; beyond the max?
BLOS 20$
MOVB #'A,STATE(A0)
RTN
20$:
; RPACK LEN,SEQ,PACKET,TYPE
RPACK D2,D3,PACKET(A0),D4 ; receive a packet (expecting filename)
JNE 500$ ; no packet received ; timeout
CMPB D4,#'D ; got a Data packet ?
JNE 60$ ; no
CMPB D3,N(A0) ; yes-is it right packet # ?
BEQ 50$ ; YES
CALL NEXTO ; NO-get next OLDTRY value in D1
CMPB D1,MAXTRY(A0) ;
BLOS 25$
MOVB #'A,STATE(A0) ; abort -retries exceeded
JMP 1000$ ; done
25$: MOVB N(A0),D1 ; D1 gets current packet #
CALL PREVP ; get previous packet #
CMPB D1,D3 ; previous packet ?
BNE 40$ ; no
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,D3,#6,PACKET(A0) ; yes-re-ack.
CLRB NUMTRY(A0) ; clear retry count
JMP 1000$ ; stay in state.
40$: MOVB #'A,STATE(A0) ; goto abort
JMP 1000$ ; done
; received valid data frame - output it
50$: CALL BUFEMP ; empty the buffer to disk
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,N(A0),#0,PACKET(A0) ; ack the data
MOVB NUMTRY(A0),OLDTRY(A0) ; reset the try counters
CLRB NUMTRY(A0) ; clear retry count
CALL BUMPP ; bump the packet #
MOVB #'D,STATE(A0) ; stick in D state.
CALL SHODOT ; tell user we moved some data
JMP 1000$ ; stay in state.
60$: CMPB D4,#'F ; file header?
BNE 80$ ; no
CALL NEXTO ; D1 gets next oldtry
CMPB D1,MAXTRY(A0) ; time to give up?
BLOS 70$ ; no
65$: MOVB #'A,STATE(A0) ; yes-abort
JMP 1000$ ; done
70$: MOVB N(A0),D1 ; get N
CALL PREVP ; calc previous packet # to D1
CMPB D1,D3 ; same ?
BNE 65$ ; no
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,D3,#0,PACKET(A0) ; yes-ack again
CLRB NUMTRY(A0) ; reset tries
JMP 1000$ ; done
80$: CMPB D4,#'Z ; end of file?
BNE 200$ ; no
CMPB D3,N(A0) ; yes-is the packet # correct?
BNE 65$ ; no-move to abort state.
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'Y,D3,#0,PACKET(A0) ; ack the Z
CALL CLOSER
LOOKUP FIO(A0) ; do file lookup
CALL GTSIZE ; to get file size
CALL ENDTM ; show elapsed time & speed
CALL DINGEM ; [015] alert user
CALL BUMPP ; bumpthepacket#
MOVB #'F,STATE(A0) ; return the F state
BR 1000$
200$: CALL CLOSER ; close file if open
CMPB D4,#'E ; error frame ?
BNE 400$ ; no
CALL PRTERR ; show it
MOVB #'A,STATE(A0) ; move to abort
JMP 1000$
400$: MOVB #'A,STATE(A0) ; goto abort state
JMP 1000$
; didnt get a packet
500$:
; SPACK TYPE,SEQ,SIZE,PACKET
SPACK #'N,N(A0),#0,PACKET(A0) ; send NAK
1000$: RTN
;;; P A C K E T U T I L I T I E S
; B U M P P - bumps the current packet mod 64. The new N is returned in D1,
; and is also updated in N(A0).
BUMPP: BCALL NEXTN
MOVB D1,N(A0)
RTN
; N E X T N - returns the next N(A0) value in D1. It does NOT update N(A0).
NEXTN: CLR D1
MOVB N(A0),D1
ADD #1,D1
ANDB #63.,D1
RTN
; N E X T O - returns the next OLDTRY(A0) value in D1.
; It does not update OLDTRY(A0).
NEXTO: CLR D1
MOVB OLDTRY(A0),D1
ADD #1,D1
ANDB #63.,D1
RTN
; P R E V P - returns the prior packet to D1 in D1. ( D1-1 mod 64. )
PREVP: SUB #1,D1
AND #63.,D1
RTN
; P R T E R R - prints the error message contained in the Error packet
PRTERR: CLR D0 ;
MOVB LDATA(A0),D0 ; get length of data field
LEA A1,DATA(A3)
TTYL ABTTTL
BR 30$
20$: MOVB (A1)+,D1
TTY
30$: DBF D0,20$
CRLF
RTN
; R P A R - get the REMOTE's send-init parameters.
; At entry, A3 indexs the packet area
; revised [21]
RPAR: MOVB #'1,CHKT(A0) ; default to 1 char checksum
MOVB #SPACE,REPT(A0) ; and no repeat
CLRB QBIN(A0) ; default to no quoting, 7 bit path
10$: LEA A1,DATA(A3) ; index the payload area
CLR D1
MOVB (A1)+,D1 ; get MAXL byte
AND #177,D1 ; strip to ASCII in case of parity
UNCHAR D1
CMPB D1,#PAKSIZ ; bigger than protocol max?
BHI 19$ ; yes, use default
15$: CMPB D1,MXPKSZ(A0) ; compare to user's max
BLO 18$ ; but no higher
MOVB MXPKSZ(A0),D1 ; use our local max
18$: CMPB D1,#10. ; MAXL should be at least 10.
BHIS 30$
19$: MOV #80.,D1 ; yes, use default MAXL of 80.
30$: MOVB D1,SPSIZ(A0) ; set send packet size
MOVB (A1)+,D1 ; get TIME byte
UNCHAR D1
MOV D1,TIMINT(A0) ; set when I should time out
MOVB (A1)+,D1 ; get NPAD byte
UNCHAR D1
MOVB D1,PAD(A0) ; set pad count.
MOVB (A1)+,D1 ; get PADC byte
CTL D1
MOVB D1,PADCHR(A0) ; set pad character
MOVB (A1)+,D1 ; get EOL byte
UNCHAR D1
MOVB D1,EOL(A0) ; set end of line char
MOVB (A1)+,D1 ; get QCTL byte
CMPB D1,#SPACE
BHI 40$
MOV #MYQUOT,D1 ; default it
40$: MOVB D1,QUOTE(A0) ; set control-quote.
CLR D2
MOVB LDATA(A0),D2 ; get size of data area
SUB #6,D2 ; have more than basic 6 bytes?
JLOS 140$ ; no more data
; get QBIN
MOVB (A1)+,D1 ; get QBIN byte
AND #177,D1 ; strip to ASCII
CMPB D1,#'Y ; will quote if we request?
BNE 50$ ; no
MOV #1,D0 ; yes
BR 80$
; allowable ranges are decimal 33-62 & 96-126. Reject all others.
50$: CMPB D1,#SPACE ; was it a space through null?
BLOS 70$ ; not legal 8b quote value
CMPB D1,#62. ; ASCII 33-62?
BLOS 60$ ; yes-use it
CMPB D1,#127. ; check high boundary of 2nd range
BHIS 70$ ; not legal 8b quote value
CMPB D1,#96. ; check lower bound of 2nd range
BHIS 60$ ; legal
BR 70$ ; not legal
60$: MOV #2,D0 ; set case 2 - we have valid 8b q
BR 80$
70$: MOV #0,D0 ; case 0 - we have no 8b q info
; D0 is 0, 1 or 2
80$: DEC D0 ; was it 0?
BCC 90$ ; no
CMPB PARITY(A0),#'N ; do we have NO parity?
SETNE QBIN(A0) ; P=None, allow full 8 bits
; P=other, mask to 7 bits
BR 110$
90$: DEC D0 ; was it 1? (quote if needed only)
BCC 100$ ; no
CMPB PARITY(A0),#'N ; do we have NO parity?
BEQ 95$ ; yes-flag 8 bits, no quoting
MOVB #'&,QBIN(A0) ; else 7 bits, default quote
BR 110$
95$: CLRB QBIN(A0)
BR 110$
100$: MOVB D1,QBIN(A0) ; got QBIN - 7 bits w/quoting
110$: SUB #1,D2
BEQ 140$ ; no more
; get CHKT
MOVB (A1)+,D1 ; get CHKT byte
;;[023] CMPB D1,#'2 ; higher than 2?
CMPB D1,DF.CHK(A0) ; higher than max user value? [023]
BHI 120$ ; yes-force to one
BEQ 130$ ; no-allow it
CMPB D1,#1 ; do not allow zero
BEQ 130$
120$: MOV #'1,D1 ; force to 1 if BOTH SIDES don't agree
130$: MOVB D1,CHKT(A0) ; set checksum method
SUB #1,D2
BEQ 140$
; get REPT
MOVB (A1)+,D1 ; get REPT byte
UNCHAR D1
MOVB D1,REPT(A0) ; set repeat prefix
140$: CMPB QUOTE(A0),#SPACE ; quote undefined ?
BNE 150$ ; no-defined
MOVB #'#,QUOTE(A0) ; yes-use default
150$: RTN
; S P A R - fill data area with send-init parameters
SPAR: LEA A1,DATA(A3) ; index payload area
CLR D1
MOVB MXPKSZ(A0),D1 ; get max packet size
CHAR D1
MOVB D1,(A1)+ ; 1 max packet size
MOV DF.TIM(A0),D1 ; get our default value
CHAR D1
MOVB D1,(A1)+ ; 2 # of seconds to my timeout
MOV #MYPAD,D1
CHAR D1
MOVB D1,(A1)+ ; 3 # of padding characters
MOV #MYPCHR,D1
CTL D1 ; the pad character translated
MOVB D1,(A1)+ ; 4
MOV #0,D1 ; we do not need an EOL this end.
CHAR D1
MOVB D1,(A1)+ ; 5 end of line character
MOV #MYQUOT,D1
MOVB D1,(A1)+ ; 6 control quoting character
; handle QBIN
MOVB QBIN(A0),D1 ; get QBIN
BEQ 40$ ; only quote on request
CMPB D1,#^O377 ; is QBIN already defined?
BNE 60$ ; yes, else
40$: MOVB #'Y,D1 ; default to quoting on request
60$: MOVB D1,(A1)+ ; 7 the optional binary quoter
MOVB DF.CHK(A0),(A1)+ ; 8 the optional checkbyte type
PARSIZ =8.
RTN
; FLUSH deletes all pending input from the input buffer
FLUSH: MOV REMOTE(A0),A5
10$: TST T.ICC(A5) ; more data?
BEQ 20$ ; no, done
TTYIN ; dump a byte
BR 10$
20$: RTN
; B U F F I L - fills a packet @A3 with data.
; we will limit data size to 3 less than actual size to allow the last
; character to be control and 8bit quoted, without look-ahead schemes.
; the worst cases are '# = # and '& = &.
; data count goes to BUFCNT(A0).
; At entry, A3 must index the data packet area to be filled,
; CHKNOW(A0) must contain the binary checkbyte size
BUFFIL: CLR D0
MOVB SPSIZ(A0),D0 ; D0 gets max msg size to remote
SUBB CHKNOW(A0),D0 ; less size of checkbyte
SUB #<3.>,D0 ; less overhead bytes
LEA A1,DATA(A3) ; index the data area
10$: CALL INBYTE ; get a data byte
TST FIO+D.SIZ(A0) ; end of file ?
BEQ 100$ ; yes
; test for high bit
BTST #7.,D1 ; no-test for eighth bit set.
BEQ 30$ ; bit 7 is clear
; handle high bit prefixing, if any
MOVB QBIN(A0),D7 ; get 8bit quote character.
BMI 20$ ; no high bit can be used
BEQ 30$ ; no 8 bit quoting needed!
MOVB D7,(A1)+ ; buffer the 8bit quote
SUB #1,D0 ; decrement the count
20$: AND #^O177,D1 ; strip to ascii
30$: MOVB D1,D2
ANDB #^O177,D2 ; D2 gets stripped version
CMPB D2,#DEL ; is it a DEL
BEQ 35$ ; this is non-printable.
; also prefix the prefix, and the high bit prefix with the prefix!
CMPB D2,QUOTE(A0) ; is this character the prefix?
BNE 32$ ; no
MOVB D2,(A1)+ ; yes-prefix it with itself
SUB #1,D0
32$: TSTB QBIN(A0) ; check 8 bit quoting
BLE 34$ ; none
CMPB D2,QBIN(A0) ; matching?
BNE 34$ ; no- [10/23/84 rpr]
MOVB QUOTE(A0),(A1)+ ; yes-quote it first
SUB #1,D0 ; less one for quote
34$: CMPB D2,#SPACE ; is it control ?
BHIS 50$ ; no-prinatble
; unctrol-ify the character, while preserving possible bit7.
35$: CTL D1 ; uncontrol-ify
40$: MOVB QUOTE(A0),(A1)+
SUB #1,D0
50$: MOVB D1,(A1)+
SUB #1,D0
BGT 10$ ; loop till filled up
100$: LEA A6,DATA(A3) ; ptr to start of data
MOV A1,D1 ; get ending ptr
SUB A6,D1 ; D1 gets outgoing data size
MOVB D1,BUFCNT(A0) ; set data count
RTN
; INBYTE gets a byte from a disk file.
INBYTE: TST FIO+D.SIZ(A0) ; EOF already?
BEQ 10$ ; yes, done
FILINB FIO(A0) ; get a byte from file
10$: RTN
; close file if it is open.
CLOSER: TSTB FIO+D.OPN(A0) ; is file open?
BEQ 10$ ; no
CLOSE FIO(A0) ; yes-close the file
CLRB FIO+D.OPN(A0) ; and clear open code!
10$: RTN
; B U F E M P - empties the incoming data contents of the packet @A3 to
; the FIO(A0) file.
BUFEMP: LEA A1,DATA(A3) ; index the data area
CLR D0
MOVB LDATA(A0),D0 ; D0 gets the count
BR 600$ ; check for 0 bytes in packet [21]
10$: CALL GETBYT ; get an input byte [10/23/84]
; doing 8bit quoting?
MOVB QBIN(A0),D2 ; get 8bit quote character
BLE 100$ ; no binary quoting
CMPB D2,D1 ; is it binary quote ?
BNE 100$ ; no
; 8bit quote received. Evaluate following characters.
MOV #^O200,D3 ; set high bit flag
CALL GETBYT ; get next byte
CALL EVALQ ; evaluate this & next chars
ORB D3,D1 ; combine evaluated char & top bit
BR 500$
100$: CLR D3 ; clear high bit flag
CALL EVALQ ; evaluate
500$: FILOTB FIO(A0) ; output the data byte
600$: TST D0
BGT 10$ ; output all bytes
RTN
; E V A L Q - evaluates the byte in D1. Expands quoted control characters,
; quoted quotes, and eighth bit quotes and quoted eighth bit quotes.
EVALQ: CMPB D1,QUOTE(A0) ; is it a quote ?
BNE 100$ ; no-just return with value
CALL GETBYT ; yes - get next byte
MOVB D1,D7
AND #^O177,D7 ; get stripped version of character
CMPB D7,QUOTE(A0) ; is it double qoute ?
BEQ 100$ ; yes-pass it literally
TSTB QBIN(A0) ; test for 8 bit quote active
BLE 10$ ; no-sending binaries
CMPB D1,QBIN(A0) ; 8bit quote prefixed by ctl quote?
BEQ 100$ ; yes-use literally.
10$: CTL D1 ; turn it to control
100$: RTN
; G E T B Y T - gets the next data byte for BUFEMP.
GETBYT: MOVB (A1)+,D1 ; get a byte
TSTB QBIN(A0) ; allowing binaries?
BEQ 10$ ; yes
AND #^O177,D1 ; no-strip to seven
10$: SUB #1,D0 ; adjust count
RTN
; R E C P A K - receives a data packet from the remote computer.
; This routine simply inputs a single packet, without performing
; packet checking or other details.
; On Entry, A3 indexs the packet destination
; On exit, D0 is the received checkbyte
; D1 is the calculated checkbyte
; D2 is the LEN
; D3 is the SEQ
; D4 is the TYPE
; Z is set if a packet is received
; CHKNOW(A0) contains binary 1,2, or 3 for checkbyte size
RECPAK:
; initialize packet receiver
CALL SETEND ; set timer ending time
MOV REMOTE(A0),A5 ; index the remote TCB
10$: CALL GETREM ; get remote character
JNE 100$ ; timeout, no data
; syncronize the packet to the mark byte (usually ^A)
AND #^O177,D1 ; strip parity here, always
CMPB D1,RMARK(A0) ; start of packet ?
BNE 10$ ; no-keep looking
20$: MOV A3,A1 ; use A1 as work register.
MOVB D1,(A1)+ ; yes-store it
; get the length from the next byte
CALL GETREM ; get LEN
JNE 100$ ; timeout, no data
CMPB D1,RMARK(A0) ; start of packet ?
BEQ 20$ ; yes-resync.
MOVB D1,(A1)+ ; else save the LEN
CALL CLRSUM ; clear checkbytes
CALL ACCUM
UNCHAR D1 ; convert to binary
MOV D1,D2 ; save the LEN
; receive the SEQ byte
30$: CALL GETREM ; get SEQ
JNE 100$ ; timeout, no data
CMPB D1,RMARK(A0) ; start of packet ?
BEQ 20$ ; yes-resync.
MOVB D1,(A1)+ ; else save the SEQ
CALL ACCUM
MOV D1,D3
UNCHAR D3 ; D3 is sequence #
; receive the TYPE byte
CALL GETREM ; get TYPE
JNE 100$ ; timeout, no data
CMPB D1,RMARK(A0) ; start of packet ?
BEQ 20$ ; yes-resync.
MOVB D1,(A1)+ ; else save the TYPE
CALL ACCUM ; update checkbyte
MOV D1,D4 ; D4 gets the type
; calc the data area size.
MOV D2,D1 ; D1 gets the binary length
CALL CALCHK ; calculate checkbyte size
CLR D0
MOVB CHKNOW(A0),D0 ; get checkbyte size
ADD #2.,D0 ; D0 gets size of SEQ,TYPE
SUB D0,D1 ; D1 gets size of data area
MOVB D1,LDATA(A0) ; save length of data
MOV D1,D0 ; D0 gets length
CMPB D0,#95.-3. ; is it legal ?
JHI 10$ ; no-toss it & try again
BR 45$ ; use DBF to control buffering of
; 0 or more characters.
; buffer the data bytes
40$: CALL GETREM ; get a byte
JNE 100$ ; timeout
CMPB D1,RMARK(A0) ; start of packet ?
BEQ 20$ ; yes-resync.
MOVB D1,(A1)+ ; store data
CALL ACCUM ; update checkbyte
45$: DBF D0,40$ ; gather packet.
; now get the checkbyte(s)
CALL GETREM ; get CHECK
JNE 100$ ; timeout, no data
CMPB D1,RMARK(A0) ; start of packet ?
JEQ 20$ ; yes-resync.
UNCHAR D1 ; convert CHECK
CLR D0
MOVB D1,D0 ; D0 gets checkbyte byte #1
CMPB CHKNOW(A0),#3. ; three character checkbyte?
BNE 50$ ; no-leave CHECK type as normal
; handle 3 byte 16 bit CCITT reverse CRC here
ANDB #^B1111,D0 ; yes, mask 1st byte to 4 bits
RORW D0,#4. ; move 1st byte bits to B15-B12
CALL GETREM ; and get second byte
JNE 100$ ; receive data fault
UNCHAR D1 ; convert it
LSLW D1,#6. ; shift 2nd byte to bits 11-6
ORW D1,D0 ; D0 gets bits 11-0
CALL GETREM ; yes- get 3rd byte
JNE 100$ ; receive data fault
UNCHAR D1 ; convert it
ORW D1,D0 ; D0 gets complete checkbytes
MOVW FRMSUM(A0),D1 ; D1 gets calculated CRC-ITT
BR 90$
; handle 2 byte 12 bit checksum here
50$: CMPB CHKNOW(A0),#2. ; two character checkbytes?
BNE 60$ ; no-leave CHECK type as normal
CALL GETREM ; yes- get second byte
JNE 100$ ; receive data fault
UNCHAR D1 ; convert it
LSL D0,#6. ; shift 1st byte to bits 11-6
ORW D1,D0 ; D0 gets bits 11-0
MOVW ASSUM(A0),D1 ; D1 gets calculated ASSUM
ANDW #^B0000111111111111,D1 ; mask it to 12 bits only
BR 90$
; handle one byte 6 bit checksum here
60$: CLR D1
MOVB ASSUM+.B0W7(A0),D1 ; {ok} get calculated sum
MOV D1,D7 ; twice
LSRW D7,#6. ; move bits 7-6 to 1-0
ANDW #3,D7 ; toss all other bits
ADDW D7,D1 ; add to sum
ANDW #^O77,D1 ; strip to 6 bits.
90$: TSTB DEBUGO(A0) ; debug mode ?
JEQ 95$ ; no
PUSH D1
CLR D1
TYPE <==Received Packet # >
MOV D3,D1
DCVT 2,OT$TRM!OT$TSP ; output as 2 characters
TYPE <, Type >
MOV D4,D1
TTY
TYPE < Length: >
MOV D2,D1
DCVT 2,OT$TRM
CRLF
TYPE <Checkbytes >
MOV @SP,D1 ; get calced sum
CMPW D0,D1 ; do they match ?
BNE 93$ ; no
TYPE <match (>
DCVT 0,OT$TRM
TYPE <)>
BR 94$
93$: TYPE <calculated = >
DCVT 0,OT$TRM
TYPE <, received = >
MOV D0,D1
DCVT 0,OT$TRM
94$: CRLF
CRLF
POP D1
95$: TSTB NOTALK(A0) ; are we showing crc errors?
BNE 98$ ; no
CMPW D0,D1 ; compare checkbytes
BEQ 96$ ; no error
TYPE c
BR 98$
; come here if packet is O.K. Check for NAK. If NAK, put n on screen
96$: CMPB D4,#'N ; was it a NAK?
BNE 98$
TYPE n
98$: CMPW D0,D1 ; compare checkbytes
RTN
; come here on timeout while waiting for packets.
; show timeouts as t's if there is a user watching.
100$: TSTB NOTALK(A0) ; TCB owned by KERMIT job?
BNE 110$ ; yes - do not type anything
TYPE <t> ; no-go ahead & show user kermit
110$: LCC #0 ; flag timeout
RTN ;
; S N D P A K - sends a packet.
; On Entry, A3 indexs the packet destination
; D2 is the LEN
; D3 is the SEQ
; D4 is the TYPE
; At exit, CHKNOW(A0) contains the checkbyte size used.
SNDPAK: TSTB DEBUGO(A0)
BEQ 30$
TYPE <Sending ">
MOVB D4,D1
TTY
TYPE <" packet # >
CLR D1
MOVB D3,D1
DCVT 0,OT$TRM
TYPE < of length >
MOVB D2,D1
DCVT 0,OT$TRM
CRLF
TYPE <Data =">
SAVE A2,D0
LEA A2,DATA(A3)
MOV D2,D0
SUB #1,D0
BMI 20$
10$: MOVB (A2)+,D1
TTY
DBF D0,10$
20$: REST A2,D0
TYPECR <">
CRLF
; send a packet to the remote KERMIT
30$: MOV REMOTE(A0),A5 ; index remote TCB
CLR D0
MOVB PAD(A0),D0 ; get pad count
MOVB PADCHR(A0),D1 ; and pad character
BR 50$
40$: TTYOUT ; send the pad character
CALL STALL ; stall, if needed
50$: DBF D0,40$ ; output pad chars while D0#0
MOV A3,A1 ; A1 is work pointer
MOVB RMARK(A0),(A1)+ ; buffer MARK character
MOV D2,D1 ; D1 gets LEN
CALL CALCHK ; calculate checkbyte size
ADDB CHKNOW(A0),D1 ; add size of checkbyte
ADD #2.,D1 ; plus SEQ & TYPE
CHAR D1 ; make it printable
MOVB D1,(A1)+ ; store LEN
CALL CLRSUM
CALL ACCUM ; update checkbyte & CRC
MOV D3,D1
CHAR D1
MOVB D1,(A1)+ ; store SEQ
CALL ACCUM ; update checkbyte & CRC
MOVB D4,(A1)+ ; store TYPE
MOVB D4,D1
CALL ACCUM ; update checkbyte & CRC
; data (if any) is already in buffer. Add it to checkbyte
CLR D1
BR 70$
60$: MOVB (A1)+,D1 ; get a byte
CALL ACCUM
70$: DBF D2,60$ ; loop till all data checked
; handle checkbyte(s) translation
; [015] add code for three character CRC
75$: CMPB CHKNOW(A0),#3. ; three character checkbyte ?
BNE 80$ ; no - try for two!
; three character checkbyte
CLR D1
MOVW FRMSUM(A0),D1 ; get all bits
CLR D7
MOVW D1,D7 ; in two regs
ROLW D7,#4. ; position bits D15-D12
ANDW #^B1111,D7 ; strip to 4 bits
CHAR D7 ; make it printable
MOVB D7,(A1)+ ; store D15-D12
MOVW D1,D7 ; in two regs
LSRW D7,#6. ; get bits D11-D6 in low 6
ANDW #^B111111,D7 ; strip to 6 bits
CHAR D7 ; make it printable
MOVB D7,(A1)+ ; store D11-D6
ANDW #^B111111,D1 ; strip to 6 bits
CHAR D1 ; make it printable
MOVB D1,(A1)+ ; store checkbyte bits D5-D0
BR 100$
80$: CMPB CHKNOW(A0),#2. ; two character checkbyte ?
BNE 90$ ; no - must be one character
; two character checkbyte
MOVW ASSUM(A0),D1 ; get all bits
MOV D1,D7 ; in two regs
LSR D7,#6. ; position bits D11-D6
AND #^O77,D7 ; strip to 6 bits
CHAR D7 ; make it printable
MOVB D7,(A1)+ ; store D11-D6
AND #^O77,D1 ; strip to 6 bits
CHAR D1 ; make it printable
MOVB D1,(A1)+ ; store checkbyte bits D5-D0
BR 100$
90$: MOVB ASSUM+.B0W7(A0),D1 ; {ok} D1 gets low eight of sum
MOV D1,D7 ; D7 gets same
AND #^O300,D7 ; take just bits 7-6.
LSR D7,#6. ; shift to bits 1-0
ADD D7,D1 ; D1 gets sum
AND #63.,D1 ; make it six bits again.
CHAR D1 ; make it prinatble
MOVB D1,(A1)+ ; store checkbyte
; check for EOL character
100$: MOVB EOL(A0),D7 ; remote need any EOL ?
BEQ 110$ ; no
MOVB D7,(A1)+ ; yes-store it
; calculate size of buffered packet from pointer displacement
110$: MOV A1,D0 ; current position
SUB A3,D0 ; less start is length
SUB #1,D0
120$: MOVB (A3)+,D1 ; get a byte
TTYOUT ; output it to REMOTE
CALL STALL ; stall ,if needed
DBF D0,120$ ; till packet is sent
RTN
; O U T B Y T - This routine outputs the byte in D1 to the remote.
OUTBYT: MOV REMOTE(A0),A5 ; get TCB pointer for remote
TTYOUT ; send the byte out
RTN
; S T A L L - stalls a certain amount of time after output in progress
; is lowered. At entry, A5 must index the output TCB.
STALL: TSTB STLCHR(A0) ; do we need to stall?
BEQ 20$ ; no
10$: CTRLC 20$ ; abort - CTS must be low
TSTB @A5
BMI 10$ ; wait for OIP to drop
CLR D7
MOVB STLCHR(A0),D7
MUL D7,#10000./100. ; transform to ticks
SLEEP D7
20$: RTN
; SREMOT - send the A1 string to the remote
SREMOT: MOV REMOTE(A0),A5 ; index to remote TCB
10$: MOVB (A1)+,D1
BEQ 100$
CMPB D1,#-1 ; is it wait byte?
BNE 20$ ; no
SLEEP #10000./2. ; yes, wait .5 seconds
BR 10$
20$: TTYOUT
BR 10$
100$: RTN
; C A L C H K - determines the current checkbyte size.
; This routine unifies the logic needed to force 1 byte checkbytes on SEND-INIT
; fields and their ACKS.
; At entry,
; D2 contains the LEN in binary
; D4 contains the packet type
; At exit, CHKNOW(A0) contains the binary value of the current checkbyte size.
CALCHK: CLR D7
MOVB CHKT(A0),D7 ; get checkbyte type
SUBB #'0,D7 ; less ASCII bias
; if NAK, we can deduce packet size from LEN
; this is useful if the 1st packet after changing checkbyte types is damaged.
; The other side will NAK, and we can recover the right length from the LEN
; of the NAK packet. (ACK packets may have filenames or discard info appended
; their size is not predictable.)
CMPB D4,#'N ; is it a NAK?
BNE 10$ ; no- use selected type
MOVB D2,D6 ; yes-get LEN
SUBB #2.,D6 ; less 2 gives checkbyte size
CMPB D6,#MAXCHK ; compare to largest supported type
BHI 30$ ; out of range - ignore bad advice
MOVB D6,D7 ; well
ADDB #'0,D6 ; D6 gets character
MOVB D6,CHKT(A0) ; force proper check type
BR 30$ ; and set binary type as well
; handle all but NAKs here
10$: TSTB RIACK(A0) ; have we recv'd "S" packet?
BNE 30$ ; yes, use
MOV #1,D7 ; no-force checkbyte type 1
30$: MOVB D7,CHKNOW(A0) ; save current checkbyte choice
RTN
; G E T R E M - gets a single character from the remote computer.
; At entry, A5 must index the REMOTE TCB
; At exit, D1 will contain the character, or a -1 for no character.
; Z will be set if a character was available for input.
GETREM: MOV #-1,D1 ; preset for no data
BR 20$
10$: SLEEP SLPVAL(A0) ; wait for more data [14]
; wait 1 character time for more date for higher throughput [14]
CTRLC 100$
GTIMEI D7
SUB FUDGE(A0),D7 ; less the fudge factor for wraparound
CMP D7,RTOUT(A0) ; EXPIRED?
BGT 200$ ; YES
20$: TST T.ICC(A5) ; any data to input ?
BEQ 10$ ; no input
CLR D1 ; pre-clear D1
TTYIN ; get a character
TSTB QBIN(A0) ; are we allowing 8 data bits?
BEQ 30$ ; yes
AND #^O177,D1 ; no-strip parity bit
30$: CMPB D1,#3. ; control-c?
BNE 40$ ; no
COMB CCOUNT(A0) ; yes-toggle /2 counter
BNE 50$ ; only one detected
JOBIDX
ORW #J.CCC,@A6 ; two detected - set control-c flag
40$: CLRB CCOUNT(A0) ; clear control-c count
50$: LCC #PS.Z
RTN
100$: LCC #0
RTN
200$: LCC #PS.V ; flag overflow for timeout
RTN
; S E T E N D - calculates and stores the value of the timeout point
; in internal format.
SETEND: CLR FUDGE(A0) ; clear wrap-around value
GTIMEI D7 ; D6 gets internal format time.
ADD TIMINT(A0),D7
MOV #24.*60.*60.,D6 ; D6 gets highest internal time+1
CMP D7,D6
BLO 10$ ; o.k. - no wraparound
SUB D6,D7 ; handle wrap-around
MOV D6,FUDGE(A0) ; set fudge factor to indicate
; time wraparound
10$: MOV D7,RTOUT(A0) ; SET TIME-OUT TIME
RTN
; G T S I Z E - gets file size in bytes. Destroys D6,D7. Assumes file
; has been looked up on FIO(A0). FSIZE(A0) contains the size on exit.
GTSIZE: MOV FIO+D.SIZ(A0),D7 ; D7 gets record size
MOV FIO+D.LEN(A0),D6 ; D6 gets # of blocks
TSTW FIO+D.ACT+.W0L15(A0) ; random file ?
BMI 10$ ; yep-straight multiply
SUB #2.,D7 ; no-subtract pointer bytes.
TSTB EXTEND(A0) ; O/S support extended disks?
BEQ 8$ ; no
SUBW FIO+D.FMT(A0),D7 ; yes, get extra link bytes (if any)
8$: SUB #1,D6 ; and less last block
10$: MUL D7,D6 ; block payload size * blocks
TSTW FIO+D.ACT+.W0l15(A0) ; random file ?
BMI 20$ ; yep.
ADD FIO+D.ACT(A0),D7 ; sequential-add last block's count
SUB #2.,D7 ; less link word in last block
TSTB EXTEND(A0) ; O/S support extended disks?
BEQ 20$ ; no
SUBW FIO+D.FMT(A0),D7 ; yes, get extra link bytes (if any)
20$: MOV D7,FSIZE(A0) ; size of the file
RTN
; send the user terminal a BELL if SET ALARM ON.
DINGEM: TSTB DING(A0) ; wake the user up?
BEQ 20$ ; no
TTYI ; yes
BYTE A.BEL,0
EVEN
20$: RTN
; S T A R T T - gets the current time and saves it in STIME(A0).
; Used to determine the elapsed time in file transfers.
STARTT: GTIMEI STIME(A0) ; save the start time
RTN
; E N D T M - calculate and display the elapsed time & effective baud rate
; for a file transfer.
; At entry, FSIZE must contain the file size in bytes.
ENDTM: TSTB NOTALK(A0) ; do we have a user terminal?
BNE 30$
TSTB ABORTF(A0) ; file aborted?
BNE 40$
GTIMEI D2 ; get current time
SUB STIME(A0),D2 ; less start time
BCC 10$ ; no midnight wraparound
ADD #24.*60.*60.,D2 ; else add 24 hours of seconds [14]
10$: ADD D2,TTIME(A0) ; add to total time
MOV FSIZE(A0),D7
ADD D7,TBYTES(A0) ; accum total bytes
INC TFILES(A0) ; accum total files
MOV D2,D4 ; save for effective baud rate
MOV FSIZE(A0),D3 ; get characters
CRLF
CALL ELAPSE
30$: RTN
40$: CRLF
TYPECR <File transfer interrupted.>
RTN
STATS: TSTB NOTALK(A0)
BNE 100$ ; no user to talk to
TYPE <A total of>
MOV TBYTES(A0),D1
DCVT 0,OT$TRM!OT$TSP!OT$LSP
TYPE <byte>
CALL PLURAL
TYPE < in>
MOV TFILES(A0),D1
DCVT 0,OT$TRM!OT$TSP!OT$LSP
TYPE <file>
CALL PLURAL
20$: TYPECR < transferred.>
CMP D1,#1
BLOS 100$ ; show cumulative effect for <1 file
MOV TBYTES(A0),D3 ; get characters
MOV TTIME(A0),D2 ; get seconds
TYPE <Total >
CALL ELAPSE
100$: RTN
; PLURAL - print an "s" if D1 is not 1.
PLURAL: CMP D1,#1 ; is it singular?
BEQ 20$ ; yes
TYPE <s> ; no, plural
20$: RTN
; ELAPSE displays the elapsed time & baud rate
; At entry, D2 contains the time, and D3 contains the number of bytes xferred
; trashes D4,D1,D6,D7,A6
ELAPSE: TYPE <elapsed time was >
CLR D1
MOV D2,D4
DIV D4,#60.*60. ; convert to hours
MOVW D4,D1
DCVT 2,OT$TRM!OT$ZER ; display hours
TYPE :
CLRW D4
SWAP D4 ; remainder to lower 16 bits
DIV D4,#60. ; make it minutes
MOVW D4,D1
DCVT 2,OT$TRM ; display minutes
TYPE :
CLRW D4
SWAP D4 ; seconds remiander to low 16
MOV D4,D1
DCVT 2,OT$TRM ; display seconds
TST D2 ; were seconds 0?
BEQ 20$ ; baud rate is infinite!
TYPE <, effective baud rate was >
MOV D3,D1
; multiply by 10 by adding 2*D1 and 8*D1
MOV D1,D7 ; duplicate
ADD D1,D1 ; double
LSL D7,#3. ; shift to make 8* old D1
ADD D7,D1 ; add to make 10 * old D1
DIV D1,D2 ; divided by seconds
AND #^O177777,D1 ; strip off remainder
DCVT 0,OT$TRM ; display it
20$: TYPECR <.> ; new line
30$: RTN
; S H O E S C displays the current escape from connect mode character.
SHOESC: TYPE <Escape character is >
MOVB KMETA(A0),D1
CALL SHOCHR
CRLF
RTN
; S H O C H R - displays in printable form the character in D1.
SHOCHR: PUSH D1
TSTB CMASK(A0) ; 7 or 8 bit terminal?
BMI 10$ ; terminal is 8 bits!
BTST #7.,D1
BEQ 10$
TYPE <%>
BR 15$
10$: TYPE < >
15$: ANDB CMASK(A0),D1
CMPB D1,#DEL
BNE 18$
TYPE DEL
BR 50$
18$: CMPB D1,#SPACE
BHIS 20$
PUSH D1
MOVW #177400!11.,D1
TCRT
TYPE ^
MOVW #177400!12.,D1
TCRT
POP D1
CTL D1 ; un-controlify it
BR 30$
20$: TYPE < >
30$: TTY
50$: POP D1
RTN
; show the notice & title & version
KERTTL: TTYL TITLE ; show the title
; show the program name & version
KERVER: TTYL TITL2
VCVT KERMIT+PH.VER,OT$TRM ; show the version #
CRLF
RTN
; S H O D O T - print a dot on user's terminal whenever a packet has been
; sent or recvd. (But don't do it when using user's terminal for I/O.)
SHODOT: TSTB NOTALK(A0) ; TCB owned by KERMIT job?
BNE 10$ ; yes - do not type dot!
TYPE <.> ; no-go ahead & show user kermit
10$: RTN ; is working
; initialize wildcarder
PREBAT:
ORB #D$BYP!D$ERC,FIO+D.FLG(A0) ; bypass error messages
CLRB ABORTB(A0) ; clear batch abort flag
CLR TFILES(A0)
CLR TBYTES(A0)
CLR TTIME(A0) ; clear total stat amounts
MOV A2,SAVSPC(A0) ; save user's file spec
CLR CMDPTR(A0) ; clear ptr to CMDLIN.SYS
CLR CMDERR(A0) ; clear CMDLIN error value
CLRB NXTCNT(A0) ; pre-clear # of times GETNXT called
TSTB WILDOK(A0) ; O.K. to use wildcarding?
JEQ 100$ ; no, don't even try!
LEA A2,CMDLNS
FSPEC CLDDB(A0) ; load the DDB
; fetch or find CMDLIN.SYS module - often in system memory
FETCH CLDDB(A0),A6 ; find or fetch it
BNE 100$ ; not found
MOV A6,CMDPTR(A0)
SAVE A0,A5
LEA A5,CMDIMP(A0)
MOV CMDPTR(A0),A6
MOV A6,D7
ADD #PH.SIZ,A6
; set up CMDLIN's internal ptrs in our impure area
MOV (A6)+,CMINI$(A5) ; CMINI offset
MOV (A6)+,CMNXT$(A5) ; CMNXT offset
MOV (A6)+,CMQRY$(A5) ; CMQRY offset
MOV (A6)+,CMCMP$(A5) ; CMCMP offset
MOV (A6)+,CMSKP$(A5) ; CMSKP offset
MOV (A6)+,CMFSP$(A5) ; CMFSP offset
ADD D7,CMINI$(A5) ; CMINI address
ADD D7,CMNXT$(A5) ; CMNXT address
ADD D7,CMQRY$(A5) ; CMQRY address
ADD D7,CMCMP$(A5) ; CMCMP address
ADD D7,CMSKP$(A5) ; CMSKP address
ADD D7,CMFSP$(A5) ; CMFSP address
; now init CMDLIN
MOV SAVSPC(A0),A2 ; user's spec
LEA A0,DFAULT ; default spec
CLR D7 ; operation flags
.CMINI
REST A0,A5 ; restore regs CMDLIN uses
MOV D6,CMDERR(A0) ; save CMDLIN error, if any
SETB CMDFLG(A0) ; flag we have CMDLIN.SYS
100$: MOV SAVSPC(A0),A2
RTN
; wildcard next spec routine
; handles a single spec if CMDLIN.SYS is not available.
; V set if end of spec
GETNXT:
PUSHB FIO+D.FLG(A0) ; save flags
PUSH FIO+D.BUF(A0) ; save buffer address (if any)
CLEAR FIO(A0),D.DDB ; clean the ddb for re-use
POP FIO+D.BUF(A0) ;
POPB FIO+D.FLG(A0) ; restore buffer address & flags
CLRB ABORTF(A0) ; clear abort file flag
TSTB CMDFLG(A0) ; do we have CMDLIN?
BNE 10$ ; yes
TSTB NXTCNT(A0) ; no, bump count
JNE 60$ ; done
INCB NXTCNT(A0)
MOV SAVSPC(A0),A2
ORB #D$BYP!D$ERC,SIO+D.FLG(A0) ; bypass error messages
FSPEC SIO(A0),LST
BR 20$ ; transfer
; handle file request via system wildcarder.
10$: MOV SAVSPC(A0),A2 ; index the spec
PUSH A5
LEA A5,CMDIMP(A0) ; index CMDLIN impure ptr
.CMNXT SIO(A0)
MOV D7,CMNEXT(A0)
POP A5
MOV A2,SAVSPC(A0) ; save the spec
MOV CMNEXT(A0),D7 ; get the flags
AND #NX$END,D7 ; end of specs?
JNE 60$ ; yes-end
; handle /Q logic if not invoking send remotely
TSTB NOTALK(A0) ; invoked remotely?
BNE 20$ ; yes, no user to query
PFILE SIO(A0)
SAVE A5
LEA A5,CMDIMP(A0) ; index CMDLIN impure ptr
.CMQRY ; ask user
REST A5
BEQ 10$ ; user didn't want to send that file
20$:
; copy filespec to working ddb
MOVW SIO+D.DEV(A0),FIO+D.DEV(A0)
MOVW SIO+D.DRV(A0),FIO+D.DRV(A0)
MOV SIO+D.FIL(A0),FIO+D.FIL(A0)
MOVW SIO+D.EXT(A0),FIO+D.EXT(A0)
MOVW SIO+D.PPN(A0),FIO+D.PPN(A0)
MOV SIO+D.CPU(A0),FIO+D.CPU(A0)
CALL GFILNM ; process the filename
INIT FIO(A0)
LOOKUP FIO(A0) ; does the file exist?
BEQ 30$ ; yes-ok, proceed
NEGB FIO+D.ERR(A0) ; normalize error code
BR 50$ ; and exit
30$: TSTW FIO+D.ACT+.W0L15(A0) ; random file ?
BPL 40$ ; no
TSTB NOTALK(A0) ; yes-we dont do these!
BNE 34$ ; no user to show!
TYPE <%Bypassing random file >
PFILE FIO(A0)
CRLF
34$: JMP 10$ ; skip the random file
40$: OPENI FIO(A0) ; open for input
50$: MOV #1,D7 ; cheap LCC #0
BR 70$
60$: LCC #PS.V ; end of spec
70$: RTN
; clear the checkbytes
CLRSUM: CLRW ASSUM(A0) ; clear checksum
CLRW FRMSUM(A0) ; and clear CRC
RTN
; accumulate the checksum & CRC
ACCUM: PUSH D1
AND #^H0FF,D1
ADDW D1,ASSUM(A0) ; handle 1 & 2 byte sums
CALL CCITT ; handle 3 byte CRC
POP D1
RTN
; x^16+x^12+x^5+1 REVERSE!!!!!
; Routine to calculate CCITT CRC for byte in D1.
; this routine breaks down the task into two nibble operations.
; based on C routine by andy lowry of columbia university.
; See page 257 of Da Cruz book.
CCITT: SAVE D2,D4,D7
MOVW FRMSUM(A0),D4 ; get remainder bits
ANDW #^H0FF,D1 ; mask to 8 bits
XORB D4,D1 ; combine
MOVW D1,D2 ; copy
RORW D2,#4. ; move bits 7-4 to 3-0
ANDW #^B1111,D2 ; strip to a nibble
ANDW #^B1111,D1 ; strip to a nibble
LSLW D2,#1
LSLW D1,#1 ; make them word offsets
; NOTE THAT [~Dx] IS OK SINCE D1 & D2 ARE STRIPPED TO A NIBBLE!
; (got to watch sign extend on word ops!)
MOVW CRCTB2[~D1],D1
MOVW CRCTAB[~D2],D7
XORW D7,D1
RORW D4,#8. ; get old B15-B8 in lo 8
ANDW #^O377,D4
XORW D1,D4 ; xor in new bits
MOVW D4,FRMSUM(A0) ; store CRC
REST D2,D4,D7
RTN
; Data tables for CRC-CCITT generation
CRCTAB: word 0
word 10201
word 20402
word 30603
word 41004
word 51205
word 61406
word 71607
word 102010
word 112211
word 122412
word 132613
word 143014
word 153215
word 163416
word 173617
CRCTB2: word 0
word 10611
word 21422
word 31233
word 43044
word 53655
word 62466
word 72277
word 106110
word 116701
word 127532
word 137323
word 145154
word 155745
word 164576
word 174367
IMPNAM: RAD50 /KERMITIMP/ ; name of user's variables module.
; This table defines the KERMIT commands and the subroutine address
DEFINE KCOM NAME, KSIZE, ADDR, HELP
WORD 10$$-.
BYTE KSIZE
ASCII /NAME/
BYTE 0
EVEN
ASCII /HELP/
BYTE 0
EVEN
10$$: WORD ADDR-.
ENDM
; K E R C O M is the main commands table for KERMIT.
KERCOM:
KCOM AMOS,1,AMOS,<Execute an AMOS command.>
KCOM CONNECT,1,CONNEC,<Connects your terminal to the remote KERMIT site.>
KCOM EXIT,1,GOODBY,<Exit from KERMIT to AMOS.>
KCOM HELP,1,HELP,<Types a summary of KERMIT commands and what they do.>
KCOM RECEIVE,1,RECEIV,<RECEIVE {filespec} receives one or more files from the remote KERMIT.>
KCOM SEND,1,SEND,<SEND {filespec} sends one or more files to remote KERMIT.>
KCOM SET,3,SET,<Set controls options: enter SET ? for more help.>
KCOM SHOW,2,SHOW,<Show displays the current SET options.>
KCOM ?,1,HELP,<The shorthand version of HELP.>
WORD 0
; S E T C O M is the SET subcommands table for SET.
SETCOM:
KCOM AUTORECEIVE,5,AUTREC,<RECEIVE command automatically sends KERMIT & SEND to remote Kermit.>
KCOM AUTOSEND,5,AUTSND,<SEND command automatically sends KERMIT & RECEIVE to remote Kermit.>
KCOM BELL,2,BELL,<Beep after each file transfer.>
KCOM BLOCKCHECK,2,BLOCK,<Block-check type: 1, 2, or 3 check bytes.>
KCOM DEBUG,2,DEBUG,<Debug option ON or OFF.>
KCOM DUPLEX,2,DUPLEX,<Set FULL or HALF duplex.>
KCOM ENDLINE,2, ENDLIN,<Packet terminator character.>
KCOM ESCAPE,2,ESCAPE,<Escape character for CONNECT.>
KCOM PACKETSIZE,8.,PAKMAX,<Maximum packet size.>
KCOM PACKETSTART,8.,PAKMRK,<Packet starting character.>
KCOM PARITY,2,SETPAR,<Denote parity type for NON-alpha remotes.>
KCOM RETRIES,1,NEWTRY,<Number of failed packet attempts that cause abort.>
KCOM STALL,1,STLVAL,<Number of hundreths of seconds to pause between characters.>
KCOM TIMEOUT,1,TIMER,<Packet time-out value in seconds.>
WORD 0
; This table defines the GETOPT list for options arguments.
DEFINE OPT NAME, KSIZE, VALUE
WORD 10$$-. ; offset to next entry
BYTE KSIZE ; # of unique bytes in entry
ASCII /NAME/ ; entry text
BYTE 0 ; terminator
EVEN ; word oriented table
10$$: WORD VALUE ; associated value
ENDM
; This defines the format of the end of the options list.
DEFINE OMSG STRING
WORD 0
ASCII /STRING/
BYTE 0
ENDM
; options list for logical options (YES, NO, 1,0, TRUE, FALSE are valid)
ONOFF:
YESNO: OPT YES,1,377
OPT NO,1,0
OPT ON,2,377
OPT OFF,2,0
OPT TRUE,1,377
OPT FALSE,1,0
OPT 1,1,377
OPT 0,1,0
OMSG <%Use YES or NO, ON or OFF, TRUE or FALSE, 1 or 0.>
EVEN
; options list for block check size
ONE23: OPT 1,1,'1
OPT 2,1,'2
OPT 3,1,'3
OPT ONE,1,'1
OPT TWO,2,'2
OPT THREE,2,'3
OPT III,3,'3
OPT II,2,'2
OPT I,1,'1
OMSG <%Use 1, 2, 3, ONE ,TWO, THREE, I, II, III to set check value size.>
EVEN
; list of valid parity settings, so you can't set parity George, but you
; can set parity Mark.
PARLST: OPT NONE,1,'N
OPT EVEN,1,'E
OPT ODD,1,'O
OPT MARK,1,'M
OPT SPACE,1,'S
OPT YES,1,'Y
OMSG <%Use None, Even, Odd, Mark, or Space.>
EVEN
; options for echoplex (see DUPLEX:)
EPLEX: OPT FULL,1,0
OPT HALF,1,377
OMSG <%Use FULL or HALF to set duplex options.>
EVEN
; S W C A S E - macro to define the switcher state table
DEFINE SWCASE STATE, ROUTE
BYTE STATE
EVEN
OFFSET ROUTE
ENDM
; S W S T A T is the table of valid SEND FILE states for KERMIT,
; and the offsets to the corresponding next routines.
SWSTAT: SWCASE 'S,SINIT
SWCASE 'F,SFILE
SWCASE 'D,SDATA
SWCASE 'Z,SEOF
SWCASE 'B,SBREAK
SWCASE 'C,COMPLT
SWCASE 'A,ABORT
BYTE 0
EVEN
; R C S T A T is the table of valid RECEIVE FILE states for KERMIT,
; and the offsets to the corresponding next routines.
RCSTAT: SWCASE 'R,RINIT ; receive init
SWCASE 'F,RFILE ; receive file
SWCASE 'D,RDATA ; receive data
SWCASE 'C,RCOMP ; receive complete
SWCASE 'A,RABOR ; receieve abort
BYTE 0
HLP1: ASCII / ========== Alpha-Kermit help ==========/
BYTE CR,CR,0
ABTTTL: ASCII /KERMIT aborting with the following error from REMOTE host:/
BYTE CR,0
; tables for GETOPT subroutine
DEFINE OPT CHAR,CODE = BYTE CHAR,CODE
SET1: ASCII / SET allows you to change the following parameters./
BYTE CR,CR,0
NONONO: ASCII /%You cannot CONNECT to your own terminal!/
BYTE CR
ASCII /You must specify the communications port name when KERMIT is invoked:/
BYTE CR
ASCII / e.g. KERMIT MODEM uses the MODEM communications port./
BYTE CR,0
TITLE:
ASCII 'Copyright 1984, 1994 Robert P. Rubendunst.'
BYTE CR
ASCII 'Alpha-Kermit by Soft Machines.'
BYTE CR
ASCII 'Permission is granted to use this software at no charge'
BYTE CR
ASCII 'provided that this message is not changed or deleted from'
BYTE CR
ASCII 'any copy of this software.'
BYTE CR,0
DEFINE TEXT ARG
ASCII ~ARG~
BYTE CR
ENDM
USAGE:
BYTE CR,CR
TEXT <Usage: KERMIT {communications-port}>
BYTE CR
TEXT < NOTE: KERMIT has two modes of operation - Local and Remote!>
BYTE CR
TEXT < LOCAL mode supports serial communications and file transfers through>
TEXT < a separate communications port, e.g. MODEM1.>
TEXT < For LOCAL mode, enter KERMIT and the name of the communications port,>
TEXT < and then a carriage return, e.g. KERMIT MODEM1.>
BYTE CR
TEXT < REMOTE mode is used to support only file transfers for REMOTE users,>
TEXT < e.g. PC users signed on to the Alpha Micro.>
TEXT < REMOTE mode uses the same port for commands and file transfers.>
TEXT < For REMOTE mode, just enter KERMIT and return.>
BYTE CR,CR
TEXT <KERMIT will display the prompt Alpha-Kermit> if you have selected LOCAL mode,>
TEXT <or REMOTE Alpha-Kermit if you have selected REMOTE mode.>
BYTE 0
CUSAGE:
BYTE CR
TEXT <You are now communicating with whatever device is connected>
TEXT <to the serial port (e.g. your modem, or another system.)>
TEXT <Data received by the serial port will be displayed on this screen.>
TEXT <Until you press the special escape character, all of your keypresses>
TEXT <will be sent out of the serial port.>
TEXT <Pressing the escape character returns you to Alpha-Kermit's command mode.>
BYTE CR
TEXT <If you are using a modem, your terminal is now "connected">
TEXT <to the modem. Consult your modem manual for instructions on>
TEXT <dialing, hanging up, changing modem settings, etc.>
BYTE CR
TEXT <Special tips for most modem users:>
TEXT < Before dialing, enter the characters ATE1Q0 and a return,>
TEXT < even though your keypresses may not be echoed on the screen.>
TEXT < Before exiting CONNECT, enter ATE0Q1 and a return!>
BYTE CR
TEXT <Have fun!>
BYTE CR,CR,0
; string that SEND command sends to remote Kermit to automatically get it
; ready to receive data.
PRESND: ASCII "KERMIT"
BYTE CR,-1
ASCII "RECEIVE"
BYTE CR,0
; string that RECEIVE command sends to remote Kermit to automatically get it
; ready to send data.
PREREC: ASCII "KERMIT"
BYTE CR,-1
ASCII "SEND " ; note no CR - RECEIVE will send the filespec later!
BYTE 0
; show command strings
SH1.0: ASCIZ "Modem Port: "
SH2.0: BYTE CR
TEXT < SET Options>
ASCIZ " Autoreceive: "
SH2.1: ASCIZ " Autosend: "
SH2.2: BYTE CR
ASCIZ " Bell: "
SH2.3: ASCIZ " Blockcheck: "
SH2.4: BYTE CR
ASCIZ " Debug: "
SH2.5: ASCIZ " Duplex: "
SH2.6: ASCIZ " Escape: "
SH2.7: BYTE CR
ASCIZ " Packet Size: "
SH2.7A:
ASCIZ " Packet Start: "
SH2.8: BYTE CR
ASCIZ " Parity: "
SH2.8A: ASCIZ " Retries: "
SH2.9: BYTE CR
ASCIZ " Stall: "
SH2.9A: ASCIZ "/100 Timeout: "
SH3.0: BYTE CR
TEXT <Received or Default Packet Parameters>
ASCIZ " Blockcheck: "
SH3.1: ASCIZ " 8Bit Quote: "
SH3.2: BYTE CR
ASCIZ " Endline: "
SH3.3: ASCIZ " Maximum Size: "
SH3.4: BYTE CR
ASCIZ " Pad Count: "
SH3.5: ASCIZ " Pad Value: "
SH3.6: BYTE CR
ASCIZ " Timeout: "
SH3.8: BYTE CR,CR,0
SH.DAS: ASCIZ "------"
SH.OFF: ASCIZ "OFF"
SH.ON: ASCIZ " ON"
SH.FUL: ASCIZ "FULL"
SH.HAL: ASCIZ "HALF"
SH.ZIP: ASCIZ "NONE"
NOSET: BYTE CR
ASCII /%Kermit cannot change the communications port parity, but setting is noted./
BYTE CR,0
TITL2: BYTE CR
ASCII 'Alpha-Kermit version '
BYTE 0
CMDLNS: ASCIZ "DSK0:CMDLIN.SYS[1,4]"
DFAULT: ASCIZ "*.*"
NMTN: ASCII "?No matching terminal name"
BYTE CR,0
RENTER: ASCII "Note: Kermit session already in progress - new port name ignored."
BYTE CR,A.BEL,0
EVEN
END END END