;PS:<TIMREK>KERMIT.M80.16,  4-May-83 17:18:47, Frank
; Reformat some long lines (comments) so that they don't confuse record (card)
; oriented systems (we sometimes ship this file over an RJE link).
;PS:<TIMREK>KERMIT.M80.15,  4-May-83 17:04:50, Frank
; Find and fix a few errors in Osborne 1 support, that crept in during
; the big merge.
;PS:<TIMREK>KERMIT.M80.14,  4-May-83 13:23:26, Frank
; Comment out ALL of Nick Bush's SET PORT stuff to eliminate some parsing 
; errors, this facility will be reinstalled later using IOBYTE switching.
;PS:<TIMREK>KERMIT.M80.13,  4-May-83 13:21:45, Frank
; Filter in some of Bernie's speedup changes for Generic/Rainbow.
; Add in DECmate-II support from someone at DEC, provided by Bernie.
; Also, specific VT180 (Robin) support has been removed, since the Generic
; code can drive the Robin at at its top speed (4800 baud). 
;PS:<TIMREK>KERMIT.M80.12, 23-Apr-83 16:19:30, Frank
; The BIG merge -- filtered in the following support from the "mainline"
; version, which was added after this (the "generic"/Rainbow version) split
; off from it:
;   Osborne 1 -- Charles Bacon, NIH
;   TRS-80 II CP/M -- Bruce Tanner, Cerritos College
;   Telcon Zorba -- Nick Bush, Stevens Institute of Technology
;   SET PORT command for Robin from Nick Bush.
; Also, changed all symbols to be 6 characters or less, to allow assembly
; by Bruce Tanner's MAC80 8080/8085 cross assmbler on the DEC-10 or -20
; Now we are back to having ONE SINGLE source for all Kermit-80's (provided
; the Osborne, Apple, Heath, Telcon, etc, have not been broken by careless
; merging).
;PS:<TIMREK>GENERI.M80.16, 23-Apr-83 13:48:42, Frank
; Make it print "statistics headers" for screen-formatting versions, but
; not for dumb-terminal versions.
;PS:<TIMREK>GENERI.M80.15, 22-Apr-83 22:04:39, Bill Catchings, Lehman Bros.
; Fix the previous merge.  Also change NOUT to output in decimal.
;PS:<KERMIT>GENERI.M80.2, 20-Apr-83 17:27:24, Frank da Cruz, Columbia U.
; Separate Generic from Rainbow Kermit.  Generic Kermit sends no
; control codes to the screen, Rainbow sends VT100 (ANSI) codes.  Rainbow
; Kermit has its own banner.  Otherwise, the two remain identical.
; This had been done before, but had to merge this with Bill's changes
; and some of Bernie's.  Still need to merge all this with the mainline
; CPM Kermit, which has new TRS80, Osborne, and Telcon support.
; Also, OSI now does generic-style screen control.
;********************** Version 3.2 *****************************
;PS:<TIMREK>NEWTST.ASM.22, 22-Apr-83 16:50:10, Bill Catchings
; Clean up and combine header messages.
;PS:<TIMREK>NEWTST.ASM.13, 22-Apr-83 14:54:33, Bill Catchings
; Eliminate conditional assembly of error messages.  Use the same for all
;  versions.
;PS:<TIMREK>NEWTST.ASM.10, 22-Apr-83 14:06:45, Bill Catchings
; Eliminate "Waiting..." messages.
;PS:<TIMREK>NEWTST.ASM.4, 22-Apr-83 13:30:57, Bill Catchings
; Remove %Bad checksum message and make sure the number of retries counter
;  is correctly update and displayed for the user.
;RP20:<EIBEN>KERMIT.ASM.1 18-Apr-83 20:18:18, B.G.Eiben DEC-Marlboro
; Completed generic CP/M support for DEC-VT180,DEC-RAINBOW using I/O byte
; control - has CONNECT command - but NO VT52 simulation (hardware has it)
; Added ^X as a synonym for X after escape character during CONNECT.
; This is the last of the "IF-ENDIF" versions - the next one will be a
; major cleanup a'la MODEM V7 with Configuration files.
;PS:<SY.WBC3>KERMIT.ASM.5, 11-Feb-83 11:19:19, Bill C.
; Add generic CP/M support.  Uses only CP/M calls, no port diddling.  Has
;  no connect command.
;PS:<KERMIT>CPMKERMIT.ASM.11, 10-Feb-83 15:47:20, Bill C.
; Add in Apple ][ support (with Softcard and D.C. Hayes Micromodem) from
; Scott Robinson at DEC-Marlboro.
;PS:<SY.WBC3>KERMIT.ASM.6,  9-Feb-83 09:13:06, Bill C.
; Add SET PARITY command. 
;PS:<KERMIT>CPMKERMIT.ASM.9,  8-Feb-83 17:01:56, Bill C.
; Lower case EQU's to hopefully avoid some spurious ASM errors.
;PS:<KERMIT>CPMKERMIT.ASM.8,  4-Feb-83 13:23:25, Bill C.
; Add Zenith Z-100 (under CP/M-85) support from Stevens (based on H-89 code.)
;PS:<KERMIT>CPMKERMIT.ASM.7,  4-Feb-83 10:14:26, Bill C.
; Add some cosmetic changes from U Tenn.
;PS:<KERMIT>CPMKERMIT.ASM.6,  4-Feb-83 10:10:19, Bill C.
;[UTK3] Add some fixes to the LOG command.
;PS:<KERMIT>CPMKERMIT.ASM.5,  4-Feb-83 09:01:39, Bill C.
;[UTK2] Fix file re-naming routine to properly index into file name.
;PS:<KERMIT>CPMKERMIT.ASM.5,  4-Feb-83 08:58:38, Bill C.
;[UTK1] Fix sending from non-connected drive.
;********************** Version 3.0 *****************************
;PS:<SY.WBC3>KERMIT.ASM.34,  3-Feb-83 15:05:31, Bill C.
; Clear line before printing file name.
;PS:<SY.WBC3>KERMIT.ASM.32,  3-Feb-83 12:26:39, Bill C.
; Fix bug that incorrectly sent files of exactly 128*n characters.
;PS:<SY.WBC3>KERMIT.ASM.29, 28-Jan-83 21:33:36, Bill C.
; Make conditional assemble under ASM and the new SYMBOL.
;PS:<SY.WBC3>KERMIT.ASM.2, 25-Jan-83 17:01:30, Bill C.
; Add KERSRV master support.
;********************** Version 2.5 *****************************
;PS:<KERMIT>CPM-KERMIT.ASM.3, 21-Jan-83 14:06:26, Bill C.
; Fix SEND to IBM; don't turn on parity in GTCHR.
;PS:<KERMIT>CPM-KERMIT.ASM.2, 19-Jan-83 16:26:48, Bill C.
; Don't let empty lines mess us up.  This is for the new CMS SP.
;PS:<KERMIT>KERMIT-CPM.ASM.118,  1-Dec-82 14:34:01, Bill C.
; Fix bug that prevented files not on connected disk from being sent.
;PS:<KERMIT>KERMIT-CPM.ASM.117,  1-Dec-82 12:40:34, Bill C.
; Finish CPM file creation switch.
;PS:<KERMIT>KERMIT-CPM.ASM.116, 30-Nov-82 17:38:11, Bill C.
; Fix bug in edit 113 which caused only null files to be sent.
;PS:<KERMIT>KERMIT-CPM.ASM.115, 30-Nov-82 16:32:09, Bill C.
; Add CPM created file switch.
;********************** Version 2.4 *****************************
;PS:<KERMIT>KERMIT.ASM.114, 22-Oct-82 16:10:23, Bill C.
; Fix parity problem in CONNECT code for the IBM.
;PS:<KERMIT>KERMIT.ASM.113, 30-Sep-82 10:29:46, Bill C.
; Fix parity problem while sending files to the IBM.
;PS:<KERMIT>KERMIT.ASM.111, 20-Jul-82 11:08:10, Bill C.
; Fix for spurious chars for the Robin.
;********************** Version 2.3 *****************************
;PS:<KERMIT>KERMIT.ASM.110, 22-Apr-82 12:29:05, Bill C.
; Turn off all VT52 emulation code for the Robin.
;PS:<KERMIT>KERMIT.ASM.101, 16-Apr-82 17:05:16, Bill C.
; Put prompt after transfer on line 7 rather than 6 so as not to clobber
;  error messages.
;PS:<KERMIT>KERMIT.ASM.101, 16-Apr-82 17:05:15, Bill C.
; Make Robin screen stuff up to date, the same as the SuperBrain's.
;PS:<KERMIT>KERMIT.ASM.98, 16-Apr-82 16:16:25, Bill C.
; Fix Robin to work as VT100 rather than VT52.
;********************** Version 2.2 *****************************
;PS:<KERMIT>KERMIT.ASM.97, 18-Mar-82 16:57:01, Bill C.
; Delete unused error messages.
;PS:<KERMIT>KERMIT.ASM.96, 17-Mar-82 18:14:41, Bill C.
; Don't die on wrong packet number.  Also, fix it so that NAKs are sent
;  if problems occur receiving file.
;PS:<KERMIT>KERMIT.ASM.95, 17-Mar-82 12:53:38, Bill C.
; On the first packet to the IBM (Send-Init) don't wait for XON.
;********************** Version 2.1 *****************************
;PS:<KERMIT>KERMIT.ASM.94, 17-Mar-82 12:28:22, Bill C.
; Put diagnostic messages under DEBUG switch.
;PS:<KERMIT>KERMIT.ASM.93, 17-Mar-82 11:15:23, Bill C.
; Fix OSI, check MNPRST not MNPORT for status.
;PS:<KERMIT>KERMIT.ASM.91,  3-Feb-82 12:28:25, Bill C.
; Fix Vector, change CONOUT to DCONIO.  Also change turn-around char to XON.
;PS:<KERMIT>KERMIT.ASM.84,  1-Feb-82 16:59:06, Bill C.
; Add in Heath and Robin support.
;********************** Version 2.0 *****************************
;PS:<KERMIT>KERMIT.ASM.77, 28-Jan-82 16:11:27, Bill C.
; Fix long send packet size bug.
;PS:<KERMIT>KERMIT.ASM.70, 27-Jan-82 10:08:25, Bill C.
; Fix data send retry problem.
;PS:<KERMIT>KERMIT.ASM.62, 26-Jan-82 13:50:58, Bill C.
; Fix long file problem.  Also spruce up set command.
;********************** Version 1.9 *****************************

; KERMIT - KL10 Error-free Reciprocol Micro Interconnect over TTY-lines

;	Version 3.1

;	Based on the KERMIT Protocol.

;	Copyright June 1981
;	Bill Catchings
;	Columbia University
;	612 W. 115th St.
;	New York City, NY  10025

; Special thanks to Frank da Cruz, Daphne Tzoar and Bernie Eiben for
;  their help and contributions.

; Fixes by U Tenn are denoted by [UTK].

	ORG	100H



TRUE	EQU	-1		; Define the boolean constants.
FALSE	EQU	NOT TRUE	; ...

debug	EQU	FALSE		; For debugging (SuperBrain only).

; Which CP/M system hardware are we building KERMIT-80 for?
; One of the following should be TRUE, the rest FALSE:
;
robin	EQU	TRUE		; DEC-VT180=Generic + VT100 screen control
brain	EQU	FALSE		; For Intertec SuperBrain.
vector	EQU	FALSE		; For Vector Graphics.
osi	EQU	FALSE		; For Ohio Scientific.
heath	EQU	FALSE		; For Heath/Zenith H89.
z100	EQU	FALSE		; For Z-100 under CP/M-85.
apple	EQU	FALSE		; For APPLE ][ with D.C. Hayes Micromodem II.
trs80	EQU	FALSE		; For TRS-80 model II (Lifeboat CP/M 2.25C)
osbrn1	EQU	FALSE		; For Osborne 1
telcon	EQU	FALSE		; For TELCON (portable)
rainbo	EQU	FALSE		; Rainbow (=Generic with VT100 screen control).
gener   EQU     FALSE		; "Generic" Kermit-80, CP/M calls only.
dmII	EQU	FALSE		; "Generic" KERMIT-80 for DECMATE II.

;* Remove these PRINTX's if you're not assembling with MAC80...

if robin
printx Assembling KERMIT-80 for the DEC VT180 "Robin"
endif

if brain
printx Assembling KERMIT-80 for the Intertec Superbrain
endif

if vector
printx Assembling KERMIT-80 for the Vector Graphics CP/M System
endif

if osi
printx Assembling KERMIT-80 for the Ohio Scientific CP/M System
endif

if heath
printx Assembling KERMIT-80 for the Heath/Zenith 89
endif

if z100
printx Assembling KERMIT-80 for the Heath/Zenith Z100 CP/M System
endif

if apple
printx Assembling KERMIT-80 for the Apple ][ with Z80 Softcard & Micromodem II
endif

if trs80
printx Assembling KERMIT-80 for the TRS-80 II CP/M System
endif

if osbrn1
printx Assembling KERMIT-80 for the Osborne 1
endif

if telcon
printx Assembling KERMIT-80 for the Telcon Zorba
endif

if rainbo
printx Assembling KERMIT-80 for the DEC Rainbow-100
endif

if dmII
printx Assembling KERMIT-80 for the DECmate II
endif

if gener
printx Assembling Generic KERMIT-80
endif

;* Remove the above PRINTX's if you're not assembling with MAC80...

IF (gener OR rainbo OR robin OR dmII)
;	This one is hopefully the last "improvement" in view of GENERIC
; Kermit. It uses for Character-I/O the BIOS-routines ( instead of the
; "normal" BDOS routines. What does it give us (hopefully) : More speed,
; higher chance of success ( I/O byte implemented in BIOS [if at all]),
; but no "extra" device handling - thats done by BDOS.
;
;	How do we "get" the call-adresses? . Location 0 has a CALL Warm-Boot
; in CP/M; which points into the second location of the BIOS JMP-Vector.The
; next three locations of the JMP-Vector point to the CONSTAT,CONIN,CONOUT
; BIOS-routines. CONOUT wants the character in C.
;
; - Bernie Eiben

iniadr:	lhld	1		;get BIOS Warmstart-address
	lxi d,3			;next adress is CONSTAT in BIOS
	dad d
	shld bconst+1		; stuff it into the call-instruction
	lxi d,3			;next adress is CONIN in BIOS
	dad d
	shld bconin+1		;
	lxi d,3			;next adress is CONOUT in BIOS
	dad d
	shld bcnout+1
	jmp start

bconst:	call $-$		; Call BIOS directly (filled in by iniadr)
	ret

bconin:	call $-$		; Call BIOS directly (filled in by iniadr)
	ret

bcnout:	call $-$		; Call BIOS directly (filled in by iniadr)
	ret
ENDIF				;(gener OR rainbo OR robin OR dmII)
;=========================================================================
; 	I/O Byte assignments (2-bit fields for 4 devices at loc 3)

;bits 6+7	LIST field
;    0		LIST is Teletype device (TTY:)
;    1		LIST is CRT device (CRT:)
;    2		LIST is Lineprinter (LPT:)
;    3		LIST is user defined (UL1:)
;
;bits 4+5	PUNCH field
;    0		PUNCH is Teletype device (TTY:)
;    1		PUNCH is high speed punch (PUN:)
;    2		PUNCH is user defined #1 (UP1:)
;    3		PUNCH is user defined #2 (UP2:)
;
;bits 2+3	READER field
;    0		READER is Teletype device (TTY:)
;    1		READER is high speed reader (RDR:)
;    2		READER is user defined #1 (UR1:)
;    3		READER is user defined #2 (UR2:)
;
;bits 0+1	CONSOLE field
;    0		CONSOLE is console printer (TTY:)
;    1		CONSOLE is CRT device (CRT:)
;    2		CONSOLE is in Batch-mode (BAT:); READER = Input, LIST = Output
;    3		CONSOLE is user defined (UC1:)
;
;=========================================================================
IF rainbo OR robin OR gener 
batio	EQU	056H		;I/O byte CON=BAT,LIST=CRT,READER=RDR
defio	EQU	095H		;I/O byte CON=CRT,LIST=LPT,READER=RDR
ENDIF				;rainbo OR robin OR gener

IF dmII
batio	EQU	042H		;I/O byte CON=BAT,LIST=CRT,READER=RDR
defio	EQU	081H		;I/O byte CON=CRT,LIST=LPT,READER=RDR
ENDIF				; dmII


bell	EQU	07O
ctrlc	EQU	03O
tab	EQU	11O
lf	EQU	12O
ff	EQU	14O
cr	EQU	15O
xon	EQU	21O
xoff	EQU	23O
esc	EQU	33O
del	EQU	177O
bdos	EQU	0005H	;Call BDOS
;Function Name		Function	Input Parameters Output Parameter
;=============		========	================ ================
;	(ALL Function Numbers are passed in Register C)
conin	EQU	01H	;Read Console	NONE		 ASCII Char in A
conout	EQU	02H	;Write Console	ASCII Char in E	 NONE
rdrin	EQU	03H	;Read Reader	NONE		 ASCII Char in A
punout	EQU	04H	;Write Punch	ASCII Char in E	 NONE
lstout	EQU	05H	;Write List	ASCII Char in E	 NONE
dconio	EQU	06H	;Direct Con I/O ASCII Char in E	 I/O Status in A
			;                                 if E=0FEH,
			;				  Input if E=0FFH
gtiob	EQU	07H	;Get I/O status NONE		 I/O Status in A
ptiob	EQU	08H	;Put I/O status	I/O Status in E	 NONE
prstr	EQU	09H	;Print String	String-Address	 NONE
;					in DE (term=$)
rdstr	EQU	0AH	;Read Buffer	Buffer-Address	Read Buffer filled
;					in DE
;	Read Buffer	Byte	Function
;			  1	Maximum Buffer Length
;			  2	Current Buffer Length (returned value)
;			3-n	Data (returned values)
;
consta	EQU	0BH	;Console Stat	NONE		LSB(A)=1 if char ready
inbdos	EQU	0DH	;Init BDOS	NONE		NONE
logdsk	EQU	0EH	;LOG-In disk	Value in E	NONE
;					A=0,B=1,...
openf	EQU	0FH	;Open File	FCB-Addr in DE	Byte Addr.of FCB,
			;				 or 0FFH if not
closf	EQU	10H	;Close File	FCB-Addr in DE	Byte Addr.of FCB,
			;				 or 0FFH if not
sfirst	EQU	11H	;Search File	FCB-Addr in DE	Byte Addr.of FCB(0-3),
			;				 or 0FFH if not
snext	EQU	12H	;Search next	FCB-Addr in DE	Byte Addr.of next FCB,
			;				 or 0FFH if not
delf	EQU	13H	;Delete File	FCB-Addr in DE	Byte Addr.of FCB(0-3),
			; 				 or 0FFH if not
readf	EQU	14H	;Read Record	FCB-Addr in DE	0=successful read
;							1=read past EOF
;							2=reading random data
writef	EQU	15H	;Write Record	FCB-Addr in DE	0=successful write
;							1=ERROR extending
;							2=End of disk data
;							255=No more DIR space
makef	EQU	16H
renam	EQU	17H	
rdlog	EQU	18H	;Ret. Log Code	NONE		Login Vector in HL
rddrv	EQU	19H	;Read Drive #	NONE		# of logged in drive in
;							(A=0,B=1,C=2....)
setdma	EQU	1AH	;Set DMA Addr.	Addr. of 128	NONE
;					byte buffer in DE
getalv	EQU	1BH	;Get All.Vect.	NONE		All.Vect in HL
wrtprt	EQU	1CH	;Write prot dsk	NONE		NONE
getrov	EQU	1DH	;Get R/O Vect.	NONE		HL= R/O Vect. value
setfat	EQU	1EH	;Set File Attr.	FCB-Addr.in DE	Dir. code in A
gtdpar	EQU	1FH	;Get DSK par.	NONE		HL=DPB Address
usrcod	EQU	20H	;Get/Set Usr.Cd	E=0FFH (get)	A=current code (get)
;					E-code (set)	A=no value (set)
rrand	EQU	21H	;Read  Random	FCB-Addr in DE	A=Return code
wrand	EQU	22H	;Write Random	FCB-Addr in DE	1=read'g unwritten data
;							2=(not used)
;							3=can't close curr. ext
;							4=seek to unwr. ext.
;							5=dir overflow(write)
;							6=seek past End of DSK
cflsz	EQU	23H	;Comp File Sz.	FCB Addr.in DE	Rand.Rec.field set to
			;				 File size
setrar	EQU	24H	;Set Rand. Rec.	FCB-Addr.in DE	Rand.Rec.field set

IF brain
baudst	EQU	60H		; Port number for baud rate setting.
baudrt	EQU	0EF00H		; Memory location where baud rates are stored.
mnport	EQU	58H
mnprts  EQU	59H
output	EQU	01H
input	EQU	02H
ENDIF				;brain

IF osi
mnport	EQU	0CF01H
mnprts  EQU	0CF00H
output	EQU	02H
input	EQU	01H
ENDIF				;osi

IF vector
mnport	EQU	04H
mnprts	EQU	05H
output	EQU	01H
input	EQU	02H
ENDIF				;vector

IF heath
mnport	EQU	330O
mnprts	EQU	335O
output	EQU	20H
input	EQU	01H
ENDIF				;heath

IF z100
mnport	EQU	0ECH
mnprts	EQU	0EDH
output	EQU	001H
input	EQU	002H
ENDIF				;z100

IF trs80
mnport	EQU	0F4H		; 0F5H for port B
mnprts	EQU	0F6H		; 0F7H for port B
output	EQU	04H
input	EQU	01H
ENDIF ;trs80

IF apple
; APPLE Slot 2 contains Micromodem II.
MNPORT	EQU	0E0A7H		; Communications Port.
mnprts	EQU	0E0A6H		; Communications Port Status.
mnmodm	EQU	0E0A5H		; Modem Control Port.
orgmod	EQU	8EH		; Modem Originate Mode.
OUTPUT	EQU	02H		; Output Buffer Empty.
INPUT	EQU	01H		; Input Register Full.
apinc1	EQU	03H		; First Init Character for 6850 ACIA (Reset)
apinc2	EQU	11H		; Second Init Character for ACIA (8-bits)
apoffh	EQU     80H		; Set if OFFHOOK
AP300	EQU	1		; 300 Baud
ENDIF				;apple

IF osbrn1
; Osborne 1 uses 6850 ACIA, but memory mapped.  Derived from Apple.
BAUDRT	EQU	0EFC1H	; Memory location where baud rates are stored.
OSTOP	EQU	4000H	; Where we move OSMOVE to at startup
OSPORT	EQU	2A01H	; Communications Port.
OSPRTS	EQU	2A00H	; Communications Port Status.
OUTPUT	EQU	02H	; Output Buffer Empty.
INPUT	EQU	01H	; Input Register Full.
OSBIN1	EQU	57H	; First Init Character for 6850 ACIA (Reset)
; (I would have thought 03, but prom code writes 57 there)
OSBI12	EQU	55H	; Second Init Character for ACIA (8-bits, 1200)
OSBI03	EQU	56H	; Second init char. for ACIA (8 bits, 300)
; (don't ask.. I don't know why SETUP writes 55 and 56 either)
ENDIF ; osbrn1

IF telcon
MNPORT	EQU	20H		; Modem data port
MNPRTS	EQU	21H		; Modem status port
OUTPUT	EQU	01H		; Transmitter empty
INPUT	EQU	02H		; Input data available
ENDIF ; telcon

;IF robin
;***** These definitions just left for information *****
;***** NOT generally found in distributed documentation ****

;pbausl EQU	90H		; The Baud-Rate register.
;prntst	EQU	49H		; Printer
;prndat	EQU	48H
;contst	EQU	41H		; Console
;condat	EQU	40H
;gentst	EQU	51H		; General port.
;gendat	EQU	50H
;comtst	EQU	59H		; COMM-Port
;comdat	EQU	58H
;output	EQU	01H		; Output ready bit.
;input	EQU	02H		; Input ready bit.
;ENDIF				;robin

IF brain OR osi OR apple OR telcon
defesc	EQU	']'-100O	; The default escape character.
ENDIF				;brain OR osi OR apple OR telcon

IF vector
defesc	EQU	'~'		; Vector can't type ']'.
ENDIF				;vector

IF robin OR heath OR z100 OR rainbo OR gener OR osbrn1 OR dmII
defesc	EQU	'\'-100O	; The default is Control \ -- it's easier B.E.
ENDIF ; robin OR heath or z100 or rainbo or gener OR osbrn1 OR dmII

IF trs80
defesc	EQU	'_'-100O	; CTRL-_ (CTRL-downarrow on TRS-80 keyboard)
ENDIF ; trs80

maxpkt  EQU	'~'-' '+2O	; Maximum size of a packet. 
maxtry	EQU	05O		; Default number of retries on a packet.
imxtry	EQU	20O		; Default number of retries send initiate.
drpsiz	EQU	5EH		; Default receive packet size.
dspsiz	EQU	20H		; Default send packet size.
dstime	EQU	08H		; Default send time out interval.
IF NOT (apple OR osbrn1)
drtime	EQU	05H		; Default receive time out interval.
ENDIF ;  NOT (apple OR osbrn1)
IF apple OR osbrn1
drtime	EQU	0AH
ENDIF ; apple OR osbrn1
dspad	EQU	00H		; Default send padding.
drpad	EQU	00H		; Default receive padding.
dspadc	EQU	00H		; Default send padding char.
drpadc	EQU	00H		; Default receive padding char.
dseol	EQU	CR		; Default send EOL char.
dreol	EQU	CR		; Default receive EOL char.
dsquot	EQU	'#'		; Default send quote char.
drquot	EQU	'#'		; Default receive quote char.
parevn	EQU	00H		; Even parity.
parmrk	EQU	03H		; Mark parity.
parnon	EQU	06H		; No parity.
parodd	EQU	09H		; Odd parity.
parspc	EQU	0CH		; Space parity.

defpar	EQU	parnon		; Default parity.
ibmpar	EQU	parmrk		; IBM COMTEN's parity.

soh	EQU	01H		; Start of header char.

fcb	EQU	5CH		; Location of File Control Block.
buff	EQU	80H		; Location of file output buffer (DMA).
bufsiz	EQU	80H		; Size of DMA.
maxfil	EQU	50H		; Maximum number of files allowed.

diasw	EQU	01H		; Default is diagnostics on.

cmkey	EQU	01H		; Parse a keyword.
cmifi	EQU	02H		; Parse an input file spec (can be wild).
cmofi	EQU	03H		; Parse an output file spec.
cmcfm	EQU	04H		; Parse a confirm.
cmtxt	EQU	05H		; Parse text.


start:	lxi h,0			; Clear out hl pair
	dad sp			; and fetch the system stack pointer
	shld oldsp		; and save for later restoral
	lxi sp,stack		; and move in our own stack.

	mvi c,prstr		; Print the version header.
	lxi d,versio
	call bdos

IF osbrn1
	lxi	h,ostop		; where we're moving it to
	lxi	d,osmove	; what we're moving
	mvi	c,osmct		; How many bytes we're moving
start1:	ldax	d
	inx	d
	mov	m,a
	inx	h
	dcr	c
	jnz	start1
	lda	baudrt
	ani	1
	sta	osbaud	; Find out what speed is current
ENDIF ; osbrn1

	call kermit		; Start things going.
	call exit1		; Finish up.

; This is the main KERMIT loop.  It prompts for and gets the users commands.

kermit:	lxi d,kerm
	call prompt		; Prompt the user.
	lxi d,comtab
	lxi h,tophlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	lxi h,kermtb		; Get the address of the jump table.
	mov c,a
	mvi b,0
	dad b
	pchl

kermtb:	jmp telnet
	jmp exit
	jmp help
	jmp log
	jmp read
	jmp send
	jmp setcom		; Set is an assembler keyword!!
	jmp show
	jmp status
	jmp finish
	jmp logout
	jmp bye
kermt2:	mvi c,prstr		; Print a string to the console.
	lxi d,ermes1		; An error message.
	call bdos
	jmp kermit		; Do it again.
kermt3:	mvi c,prstr		; Print a string to the console.
	lxi d,ermes3		; An error message.
	call bdos
	jmp kermit		; Do it again.

;	RECEIVE command

read:	lxi d,data		; Where to put the text (if any.)
	mvi a,cmtxt
	call comnd		; Get either some text or a confirm.
	 jmp kermt3		;  Didn't get anything.
	cpi 0			; Get any chars?
	jz read1		; Nope, just a regular send.
	sta argblk+1		; Store the number of chars.
	xchg			; Get pointer into HL.
	mvi m,'$'		; Put in a dollar sign for printing.
	call init		; Clear the line and initialize the buffers.
	mvi c,prstr		; Position cursor.
	lxi d,scrfln
	call bdos
	mvi c,prstr		; Print the file name.
	lxi d,data
	call bdos
	mvi a,0			; Start a packet zero.
	sta argblk
	mvi a,'R'		; Receive init packet.
	call spack		; Send the packet.
	 jmp kermt3		;  Die!
	jmp read12

read1:	call init		; Clear the line and initialize the buffers.
read12:	mvi a,0
	lxi h,0
	shld numpkt		; Set the number of packets to zero.
	shld numrtr		; Set the number of retries to zero.
	sta pktnum		; Set the packet number to zero.
	sta numtry		; Set the number of tries to zero.
	mvi c,prstr		; Position cursor.
	lxi d,scrnrt
	call bdos
	lxi h,0
	call nout		; Write the number of retries.
	mvi a,'R'
	sta state		; Set the state to receive initiate.
read2:	mvi c,prstr		; Position cursor.
	lxi d,scrnp
	call bdos
	lhld numpkt
	call nout		; Write the number of packets.
	lda state		; Get the state.
	cpi 'D'			; Are we in the data send state?
	jnz read3
	call rdata
	jmp read2
read3:	cpi 'F'			; Are we in the file receive state?
	jnz read4
	call rfile		; Call receive file.
	jmp read2
read4:	cpi 'R'			; Are we in the receive initiate state?
	jnz read5
	call rinit
	jmp read2
read5:	cpi 'C'			; Are we in the receive complete state?
	jnz read6
	lxi d,infms3		; Plus a little cuteness.
	call finmes
	jmp kermit
read6:	cpi 'A'			; Are we in the receive abort state?
	jnz read7
	lxi d,infms4		; Plus a little cuteness.
	call finmes
	jmp kermit
read7:	lxi d,infms4		; Plus a little cuteness.
	call finmes
	jmp kermit

;	Initialize buffers and clear line.

init:	mvi c,prstr		; Put Banner on screen.
	lxi d,outlin
	call bdos

IF NOT (gener OR osi)
	mvi c,prstr		; Put statistics headers on the screen
	lxi d,outln2		;  only for screen-formatting versions.
	call bdos
ENDIF ; NOT (gener OR osi)

init1:	mvi a,bufsiz		; Buffer size.
	sta chrcnt		; Number of chars left.
	lxi h,buff		; Addr for beginning.
	shld bufpnt		; Store addr for beginning.
	ret

;	Receive routines

;	Receive init

rinit:	lda numtry		; Get the number of tries.
	cpi imxtry		; Have we reached the maximum number of tries?
	jm rinit2
	lxi d,ermes4
	call error3		; Move cursor and print an error message.
	jmp abort		; Change the state to abort.
rinit2:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	call rpack		; Get a packet.
	 jmp nak		;  Trashed packet: nak, retry.
	cpi 'S'			; Is it a send initiate packet?
	jnz rinit3		; If not see if its an error.
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	lda argblk		; Returned packet number.  (Synchronize them.)
	inr a			; Increment it.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda argblk+1		; Get the number of arguments received.
	lxi h,data		; Get a pointer to the data.
	call spar		; Get the data into the proper variables.
	lxi h,data		; Get a pointer to our data block.
	call rpar		; Set up the receive parameters.
	sta argblk+1		; Store the returned number of arguments.
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	mvi a,'F'		; Set the state to file send.
	sta state
	ret
rinit3:	cpi 'E'			; Is it an error packet.
	jnz nak0		; If not NAK whatever it is.
	call error
	jmp abort

; These are some utility routines.

;	Abort

abort:	mvi a,'A'		; Otherwise abort.
	sta state
	ret

;	NAK

nak0:	call updrtr		; Update number of retries.

nak:	lda pktnum		; Get the packet number we're waiting for.
	sta argblk
	mvi a,0			; No data.
	sta argblk+1
	mvi a,'N'		; NAK that packet.
	call spack
	 jmp abort		;  Give up.
	ret			; Go around again.

updrtr:	mvi c,prstr		; Position cursor.
	lxi d,scrnrt
	call bdos
	lhld numrtr
	inx h			; Increment the number of retries
	shld numrtr
	call nout		; Write the number of retries.
	ret

;	This routine sets up the data for init packet (either the
;	Send_init or ACK packet).

rpar:	lda rpsiz		; Get the receive packet size.
	adi ' '			; Add a space to make it printable.
	mov m,a			; Put it in the packet.
	inx h			; Point to the next char.
	lda rtime		; Get the receive packet time out.
	adi ' '			; Add a space.
	mov m,a			; Put it in the packet.
	inx h
	lda rpad		; Get the number of padding chars.
	adi ' '
	mov m,a
	inx h
	lda rpadch		; Get the padding char.
	adi 100O		; Uncontrol it.
	ani 7FH
	mov m,a
	inx h
	lda reol		; Get the EOL char.
	adi ' '
	mov m,a
	inx h
	lda rquote		; Get the quote char.
	mov m,a
	inx h
	mvi a,06H		; Six pieces of data.
	ret


;	This routine reads in all the send_init packet information.

spar:	sta temp4		; Save the number of arguments.
	mov a,m			; Get the max packet size.
	sbi ' '			; Subtract a space.
	sta spsiz		; Save it.
	lda temp4
	cpi 3			; Fewer than three pieces?
	rm			; If so we are done.
	inx h
	inx h			; Increment past the time out info.
	mov a,m			; Get the number of padding chars.
	sbi ' '
	sta spad
	lda temp4
	cpi 4			; Fewer than four pieces?
	rm			; If so we are done.
	inx h
	mov a,m			; Get the padding char.
	adi 100O		; Re-controlify it.
	ani 7FH
	sta spadch
	lda temp4
	cpi 5			; Fewer than five pieces?
	rm			; If so we are done.
	inx h
	mov a,m			; Get the EOL char.
	sbi ' '
	sta seol
	lda temp4
	cpi 6			; Fewer than six pieces?
	rm			; If so we are done.
	inx h
	mov a,m			; Get the quote char.
	sta squote
	ret

;	Receive file

rfile:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm rfile1
	lxi d,ermes5
	call error3		; Move cursor and print an error message.
	jmp abort		; Change the state to abort.
rfile1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	call rpack		; Get a packet.
	 jmp nak		;  Trashed packet: nak, retry.
	cpi 'S'			; Is it a send initiate packet?
	jnz rfile2		;  No, try next type.
	lda oldtry		; Get the number of tries.
	cpi imxtry		; Have we reached the maximum number of tries?
	jm rfil12		; If not proceed.
	lxi d,ermes4
	call error3		; Move cursor and print an error message.
	jmp abort		; Change the state to abort.
rfil12:	inr a			; Increment it.
	sta oldtry		; Save the updated number of tries.
	lda pktnum		; Get the present packet number.
	dcr a			; Decrement.
	mov b,a
	lda argblk		; Get the packet's number
	cmp b			; Is the packet's number one less than now?
	jnz nak0		; No, NAK and try again.
	call updrtr		; Update the retry count.
	mvi a,0
	sta numtry		; Reset the number of tries.
	lxi h, data		; Get a pointer to our data block. 
	call rpar		; Set up the parameter information.
	sta argblk+1		; Save the number of arguments.
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	ret
rfile2:	cpi 'Z'			; Is it an EOF packet?
	jnz rfile3		;  No, try next type.
	lda oldtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm rfil21		; If not proceed.
	lxi d,ermes6
	call error3		; Move cursor and print an error message.
	jmp abort		; Change the state to abort.
rfil21:	inr a			; Increment it.
	sta oldtry		; Save the updated number of tries.
	lda pktnum		; Get the present packet number.
	dcr a			; Decrement.
	mov b,a
	lda argblk		; Get the packet's number
	cmp b			; Is the packet's number one less than now?
	jnz nak0		; No, NAK it and try again.
	call updrtr		; Update the number of retries.
	mvi a,0
	sta numtry		; Reset number of tries.
	sta argblk+1		; No data.  (The packet number is in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	ret
rfile3:	cpi 'F'			; Start of file?
	jnz rfile4
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	jnz nak0		; No, NAK it and try again.
	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	call gofil		; Get a file to write to.
	 jmp abort
	call init1		; Initialize all the buffers.
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0	
	sta numtry		; Reset the number of tries.
	sta argblk+1		; No data.  (The packet number is in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mvi a,'D'		; Set the state to data receive.
	sta state
	ret
rfile4:	cpi 'B'			; End of transmission.
	jnz rfile5
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	jnz nak0		; No, NAK it and try again.
	mvi a,0			; No data.  (Packet number already in argblk).
	sta argblk+1
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mvi a,'C'		; Set the state to complete.
	sta state
	ret
rfile5:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Receive data

rdata:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm rdata1
	lxi d,erms10
	call error3		; Display error message.
	jmp abort		; Change the state to abort.
rdata1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	call rpack		; Get a packet.
	 jmp nak		;  Trashed packet: nak, retry.
	cpi 'D'			; Is it a data packet?
	jnz rdata2		;  No, try next type.
rdat11:	lda pktnum		; Get the present packet number.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number correct?
	jz rdat14
	lda oldtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm rdat12		; If not proceed.
	lxi d,erms10
	call error3		; Display err msg.
	jmp abort		; Change the state to abort.
rdat12:	inr a			; Increment it.
	sta oldtry		; Save the updated number of tries.
	lda pktnum		; Get the present packet number.
	dcr a			; Decrement.
	mov b,a
	lda argblk		; Get the packet's number
	cmp b			; Is the packet's number one less than now?
	jnz nak0		; No, NAK it and try again.
	call updrtr		; Update the number of retries.
	mvi a,0
	sta numtry		; Reset number of tries.
	sta argblk+1		; No data.  (The packet number is in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	ret
rdat14:	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	lda argblk+1		; Get the length of the data.
	call ptchr
	 jmp abort		;  Unable to write out chars; abort.
	mvi a,0
	sta numtry		; Reset the number of tries.
	sta argblk+1		; No data.  (Packet number still in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rdata2:	cpi 'F'			; Start of file?
	jnz rdata3		;  No, try next type.
	lda oldtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm rdat21		; If not proceed.
	lxi d,ermes5
	call error3		; Display err msg.
	jmp abort		; Change the state to abort.
rdat21:	inr a			; Increment it.
	sta oldtry		; Save the updated number of tries.
	lda pktnum		; Get the present packet number.
	dcr a			; Decrement.
	mov b,a
	lda argblk		; Get the packet's number
	cmp b			; Is the packet's number one less than now?
	jnz nak0		; No, NAK it and try again.
	call updrtr		; Update the number of retries.
	mvi a,0
	sta numtry		; Reset number of tries.
	sta argblk+1		; No data.  (The packet number is in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	ret
rdata3:	cpi 'Z'			; Is it a EOF packet?
	jnz rdata4		; Try and see if its an error.
	lda pktnum		; Get the present packet number.
	mov b,a
	lda argblk		; Get the packet's number
	cmp b			; Is the packet's number correct?
	jnz nak0		; No, NAK it and try again.
	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
rdat33:	lhld bufpnt		; Get the dma pointer.
	lda chrcnt		; Get the number of chars left in the DMA.
rdat34:	dcr a			; Lower the count.
	cpi 0
	jm rdat35		; If full then stop.
	mvi m,'Z'-100O		; Put in a ^Z for EOF.
	inx h			; Point to the next space.
	jmp rdat34
rdat35:	call outbuf		; Output the last buffer.
	 jmp abort		;  Give up if the disk is full.
	mvi c,closf		; Close up the file.
	lxi d,fcb
	call bdos
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	sta argblk+1		; No data.  (The packet number is in argblk.)
	mvi a,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mvi a,'F'
	sta state
	ret
rdata4:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Send command

send:	mvi a,cmifi		; Parse an input file spec.
	lxi d,fcb		; Give the address for the FCB.
	call comnd
	 jmp kermit		;  Give up on bad parse.
send1:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermit		;  Didn't get a confirm.
send11:	mvi a,0			; Zero the fcb list number.
	sta fcbnum
	mvi c,sfirst		; Get the first file.
	lxi d,fcb
	call bdos
	cpi 0FFH		; Any found?
	jnz send12
	lxi d,erms15
	call error3		; Display error msg.
	jmp kermit
send12:	lxi h,buff		; Get the right offset in the buffer.
	rlc
	rlc
	rlc
	rlc
	rlc
	add l
	mov l,a
	shld bufpnt
	lda fcb			;[UTK1] Get our drive spec.
	mov m,a			;[UTK1] Put it in fcb in buffer too.
	lxi h,fcbblk		; Get the base address of the list. 
	lda fcbnum		; Get the FCB number.
	rlc			; Compute the offset.
	rlc
	rlc
	rlc
	mov c,a			; Add it to the base of the list.
	mvi b,0
	dad b
	shld fcbptr
	lda fcbnum
	adi 1
	sta fcbnum
	mvi b,0
send13:	lhld bufpnt		; Get next char.
	mov a,m
	inx h
	shld bufpnt
	lhld fcbptr		; Put the char in the FCB.
	mov m,a
	inx h
	shld fcbptr
	inr b
	mov a,b
	cpi 10H			; Done?
	jm send13
	mvi c,snext		; Get the next file.
	lxi d,fcb
	call bdos
	cpi 0FFH		; Any found, go move the fcb into the list.
	jnz send12
	lda fcbnum
	sui 1
	sta fcbnum
	lxi h,fcbblk		; Get the base address of the list.
	rlc			; Compute the offset.
	rlc
	rlc
	rlc
	mov c,a			; Add it to the base of the list.
	mvi b,0
	dad b
	shld bufpnt
	lxi h,fcb
	shld fcbptr
	mvi b,0
send14:	lhld bufpnt		; Get next char.
	mov a,m
	inx h
	shld bufpnt
	lhld fcbptr		; Put the char in the FCB.
	mov m,a
	inx h
	shld fcbptr
	inr b
	mov a,b
	cpi 10H			; Done?
	jm send14
	call init		; Clear the line and initialize the buffers.
	mvi a,0
	sta pktnum		; Set the packet number to zero.
	sta numtry		; Set the number of tries to zero.
	lxi h,0
	shld numpkt		; Set the number of packets to zero.
	shld numrtr		; Set the number of retries to zero.
	mvi c,prstr		; Position cursor.
	lxi d,scrnrt
	call bdos
	lxi h,0
	call nout		; Write the number of retries.
	mvi a,'S'
	sta state		; Set the state to receive initiate.
send2:	mvi c,prstr		; Position cursor.
	lxi d,scrnp
	call bdos
	lhld numpkt
	call nout		; Write the packet number.
	lda state		; Get the state.
	cpi 'D'			; Are we in the data send state?
	jnz send3
	call sdata
	jmp send2
send3:	cpi 'F'			; Are we in the file send state?
	jnz send4
	call sfile		; Call send file.
	jmp send2
send4:	cpi 'Z'			; Are we in the EOF state?
	jnz send5
	call seof
	jmp send2
send5:	cpi 'S'			; Are we in the send initiate state?
	jnz send6
	call sinit
	jmp send2
send6:	cpi 'B'			; Are we in the eot state?
	jnz send7
	call seot
	jmp send2
send7:	cpi 'C'			; Are we in the send complete state?
	jnz send8
	lxi d,infms3		; Plus a little cuteness.
	call finmes
	jmp kermit
send8:	cpi 'A'			; Are we in the send abort state?
	jnz send9
	lxi d,infms4		; Plus a little cuteness.
	call finmes
	jmp kermit
send9:	lxi d,infms4		; Plus a little cuteness.
	call finmes
	jmp kermit

;	Send routines

;	Send initiate

sinit:	lda numtry		; Get the number of tries.
	cpi imxtry		; Have we reached the maximum number of tries?
	jm sinit2
	lxi d,erms14
	call error3		; Display ermsg
	jmp abort		; Change the state to abort.
sinit2:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	lxi h, data		; Get a pointer to our data block.
	call rpar		; Set up the parameter information.
	sta argblk+1		; Save the number of arguments.
	lda numpkt		; Get the packet number.
	sta argblk
	mvi a,'S'		; Send initiate packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	call rpack		; Get a packet.
	 jmp r			;  Trashed packet don't change state, retry.
	cpi 'Y'			; ACK?
	jnz sinit3		; If not try next.
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	rnz			; If not try again.
	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda argblk+1		; Get the number of pieces of data.
	lxi h,data		; Pointer to the data.
	call spar		; Read in the data.
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	mvi a,'F'		; Set the state to file send.
	sta state
	call getfil		; Open the file.
	 jmp abort		;  Something is wrong, die.
	ret
sinit3:	cpi 'N'			; NAK?
	jnz sinit4		; If not see if its an error.
	call updrtr		; Update the number of retries.
	lda pktnum		; Get the present packet number.
	inr a			; Increment.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number one more than now?
	rnz			; If not assume its for this packet, go again.
	mvi a,0
	sta numtry		; Reset number of tries.
	mvi a,'F'		; Set the state to file send.
	sta state
	ret
sinit4:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Send file header 

sfile:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm sfile1
	lxi d,erms14
	call error3
	jmp abort		; Change the state to abort.
sfile1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	lxi h, data		; Get a pointer to our data block.
	shld datptr		; Save it.
	lxi h,fcb+1		; Pointer to the file name in the FCB.
	shld fcbptr		; Save position in FCB.
	mvi b,0			; No chars yet.
	mvi c,0
sfil11:	mov a,b
	cpi 8H			; Is this the ninth char?
	jnz sfil12		; If not proceed.
	mvi a,'.'		; Get a dot.
	lhld datptr
	mov m,a			; Put the char in the data packet.
	inx h
	shld datptr		; Save position in data packet.
	inr c
sfil12:	inr b			; Increment the count.
	mov a,b
	cpi 0CH			; Twelve?
	jp sfil13
	lhld fcbptr
	mov a,m
	inx h
	shld fcbptr		; Save position in FCB.
	cpi '!'			; Is it a good character?
	jm sfil11		; If not get the next.
	lhld datptr
	mov m,a			; Put the char in the data packet.
	inx h
	shld datptr		; Save position in data packet.
	inr c
	jmp sfil11		; Get another.
sfil13:	mov a,c			; Number of char in file name.
	sta argblk+1
	lhld datptr
	mvi a,'$'
	mov m,a			; Put in a dollar sign for printing.
	mvi c,prstr		; Position cursor.
	lxi d,scrfln
	call bdos
	mvi c,prstr		; Print the file name.
	lxi d,data
	call bdos
	lda pktnum		; Get the packet number.
	sta argblk
	mvi a,'F'		; File header packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	call rpack		; Get a packet.
	 jmp r			;  Trashed packet don't change state, retry.
	cpi 'Y'			; ACK?
	jnz sfile2		; If not try next.
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	rnz			; If not hold out for the right one.
sfil14:	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
sfil15:	mvi a,0			; Get a zero.
	sta fcb+20H		; Set the record number to zero.
	sta eoflag		; Indicate not EOF.
	mvi a,0FFH
	sta filflg		; Indicate file buffer empty.
	call gtchr
	 jmp sfil16		; Error go see if its EOF.
	jmp sfil17		; Got the chars, proceed.
sfil16:	cpi 0FFH		; Is it EOF?
	jnz abort		; If not give up.
	mvi a,'Z'		; Set the state to EOF.
	sta state
	ret
sfil17:	sta size		; Save the size of the data gotten.
	mvi a,'D'		; Set the state to data send.
	sta state
	ret
sfile2:	cpi 'N'			; NAK?
	jnz sfile3		; Try if error packet.
	call updrtr		; Update the number of retries.
	lda pktnum		; Get the present packet number.
	inr a			; Increment.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number one more than now?
	rnz			; If not go try again.
	jmp sfil14		; Just as good as a ACK; go to the ACK code.
sfile3:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Send data

sdata:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm sdata1
	lxi d,erms14
	call error3
	jmp abort		; Change the state to abort.
sdata1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	lxi h, data		; Get a pointer to our data block.
	shld datptr		; Save it.
	lxi h,filbuf		; Pointer to chars to be sent.
	shld cbfptr		; Save position in char buffer.
	mvi b,1			; First char.
sdat11:	lhld cbfptr
	mov a,m
	inx h
	shld cbfptr		; Save position in char buffer.
	lhld datptr
	mov m,a			; Put the char in the data packet.
	inx h
	shld datptr		; Save position in data packet.
	inr b			; Increment the count.
	lda size		; Get the number of chars in char buffer.
	cmp b			; Have we transfered that many?
	jp sdat11		; If not get another.
	lda size		; Number of char in char buffer.
	sta argblk+1
	lda pktnum		; Get the packet number.
	sta argblk
	mvi a,'D'		; Data packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	call rpack		; Get a packet.
	 jmp r			;  Trashed packet don't change state, retry.
	cpi 'Y'			; ACK?
	jnz sdata2		; If not try next.
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	rnz			; If not hold out for the right one.
sdat12:	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	call gtchr
	 jmp sdat13		; Error go see if its EOF.
	sta size		; Save the size of the data gotten.
	ret
sdat13:	cpi 0FFH		; Is it EOF?
	jnz abort		; If not give up.
	mvi a,'Z'		; Set the state to EOF.
	sta state
	ret
sdata2:	cpi 'N'			; NAK?
	jnz sdata3		; See if is an error packet.
	call updrtr		; Update the number of retries.
	lda pktnum		; Get the present packet number.
	inr a			; Increment.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number one more than now?
	rnz			; If not go try again.
	jmp sdat12		; Just as good as a ACK; go to the ACK code.
sdata3:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Send EOF

seof:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm seof1
	lxi d,erms14
	call error3
	jmp abort		; Change the state to abort.
seof1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	lda pktnum		; Get the packet number.
	sta argblk
	mvi a,0
	sta argblk+1		; No data.
	mvi a,'Z'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	call rpack		; Get a packet.
	 jmp r			;  Trashed packet don't change state, retry.
	cpi 'Y'			; ACK?
	jnz seof2		; If not try next.
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	rnz			; If not hold out for the right one.
seof12:	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	mvi c,closf		; Close the file.
	lxi d,fcb
	call bdos
;* Check if successful
	call gtnfil		; Get the next file.
	 jmp seof13		;  No more.
	mvi a,'F'		; Set the state to file send.
	sta state
	ret
seof13:	mvi a,'B'		; Set the state to EOT.
	sta state
	ret
seof2:	cpi 'N'			; NAK?
	jnz seof3		; Try and see if its an error packet.
	call updrtr		; Update the number of retries.
	lda pktnum		; Get the present packet number.
	inr a			; Increment.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number one more than now?
	rnz			; If not go try again.
	jmp seof12		; Just as good as a ACK; go to the ACK code.
seof3:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	Send EOT

seot:	lda numtry		; Get the number of tries.
	cpi maxtry		; Have we reached the maximum number of tries?
	jm seot1
	lxi d,erms14
	call error3
	jmp abort		; Change the state to abort.
seot1:	inr a			; Increment it.
	sta numtry		; Save the updated number of tries.
	lda pktnum		; Get the packet number.
	sta argblk
	mvi a,0
	sta argblk+1		; No data.
	mvi a,'B'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort		;  Failed, abort.
	call rpack		; Get a packet.
	 jmp r			;  Trashed packet don't change state, retry.
	cpi 'Y'			; ACK?
	jnz seot2		; If not try next.
	lda pktnum		; Get the packet number.
	mov b,a
	lda argblk
	cmp b			; Is it the right packet number?
	rnz			; If not hold out for the right one.
seot12:	inr a			; Increment the packet number.
	ani 3FH			; Turn off the two high order bits.
	sta pktnum		; Save modulo 64 of the number.
	lhld numpkt
	inx h			; Increment the number of packets.
	shld numpkt
	lda numtry		; Get the number of tries.
	sta oldtry		; Save it.
	mvi a,0
	sta numtry		; Reset the number of tries.
	mvi a,'C'		; Set the state to file send.
	sta state
	ret
seot2:	cpi 'N'			; NAK?
	jnz seot3		; Is it error.
	call updrtr		; Update the number of retries.
	lda pktnum		; Get the present packet number.
	inr a			; Increment.
	mov b,a
	lda argblk		; Get the packet's number.
	cmp b			; Is the packet's number one more than now?
	rnz			; If not go try again.
	jmp seot12		; Just as good as a ACK; go to the ACK code.
seot3:	cpi 'E'			; Is it an error packet.
	jnz abort
	call error
	jmp abort

;	File routines

;	Output the chars in a packet.

ptchr:	sta temp1		; Save the size.
	lxi h,data		; Beginning of received packet data.
	shld outpnt		; Remember where we are.
	lda rquote
	mov b,a			; Keep the quote char in b.
ptchr1:	lxi h,temp1
	dcr m			; Decrement # of chars in packet.
	jm rskp			; Return successfully if done.
	lxi h,chrcnt		; Number of chars remaining in dma.
	dcr m			; Decrement.
	jp ptchr2		; Continue if space left.
	call outbuf		; Output it if full.
	 jmp r			;  Error return if disk is full.
ptchr2:	lhld outpnt		; Get position in output buffer.
	mov a,m			; Grab a char.
	inx h
	shld outpnt		; and bump pointer.
	cmp b			; Is it the quote char?
	jnz ptchr4		; If not proceed.
	mov a,m			; Get the quoted character
	inx h
	shld outpnt		; and bump pointer.
	lxi h,temp1
	dcr m			; Decrement # of chars in packet.
	mov d,a			; Save the char.
	ani 80H			; Turn off all but the parity bit.
	mov e,a			; Save the parity bit.
	mov a,d			; Get the char.
	ani 7FH			; Turn off the parity bit.
	cmp b			; Is it the quote char?
	jz ptchr3		; If so just go write it out.
	mov a,d			; Get the char.
	adi 40H			; Make the character a control char again.
	ani 7FH			; Modulo 128.
ptchr3:	ora e			; Or in the parity bit.
ptchr4:	lhld bufpnt		; Destination buffer.
	mov m,a			; Store it.
	inx h
	shld bufpnt		; Update the pointer
	jmp ptchr1		; and loop to next char.

	; output the buffer, reset bufpnt and chrcnt

outbuf:	push b
	mvi c,writef		; The write code.
	lxi d,fcb
	call bdos		; Write the record.
	pop b
	cpi 0			; Successful.
	jz outbf1
	lxi d,erms11
	call error3
	ret
outbf1:	lxi h,buff		; Addr for beginning.
	shld bufpnt		; Store addr for beginning.
	mvi a,bufsiz-1		; Buffer size.
	sta chrcnt		; Number of chars left.
	jmp rskp

;	Get the chars from the file.

gtchr:	lda squote		; Get the quote char.
	mov c,a			; Keep quote char in c.
	lda filflg		; Get the file flag.
	cpi 0			; Is there anything in the DMA?
	jz gtchr0		; Yup, proceed.
	mvi b,0			; No chars yet.
	call inbuf
	 jmp gtceof		; No more chars, go return EOF.
gtchr0:	lda spsiz		; Get the maximum packet size.
	sui 5			; Subtract the overhead.
	sta temp1		; This is the number of chars we are to get.
	lxi h,filbuf		; Where to put the data.
	shld cbfptr		; Remember where we are.
	mvi b,0			; No chars.
gtchr1:	lda temp1
	dcr a			; Decrement the number of chars left.
	jp gtchr2		; Go on if there is more than one left.
	mov a,b			; Return the count in A.
	jmp rskp

gtchr2:	sta temp1
	lda chrcnt		; Space left in the DMA.
	dcr a
;* Can improve order here.
	jm gtchr3
	sta chrcnt
	jmp gtchr4

gtchr3:	call inbuf		; Get another buffer full.
	 jmp gtch30		;  If no more return what we got.
	jmp gtchr4		; If we got some, proceed.
gtch30:	mov a,b			; Return the count in A.
	cpi 0			; Get any chars?
	jnz rskp		; If so return them.
	jmp gtceof		; If not, say we found the end of the file.

gtchr4:	lhld bufpnt		; Position in DMA.
	mov a,m			; Get a char from the file.
	inx h
	shld bufpnt
	mov d,a			; Save the char.
	ani 80H			; Turn off all but parity.
	mov e,a			; Save the parity bit.
	mov a,d			; Restore the char.
	ani 7FH			; Turn off the parity.
	cpi ' '			; Compare to a space.
	jm gtchr5		; If less then its a control char, handle it.
	cpi del			; Is the char a delete?
	jz gtchr5		; Go quote it.
	cmp c			; Is it the quote char?
	jnz gtchr8		; If not proceed.
	lxi h,temp1		; Point to the char total remaining.
	dcr m			; Decrement it.
	lhld cbfptr		; Position in character buffer.
	mov m,a			; Put the char in the buffer.
	inx h
	shld cbfptr
	inr b			; Increment the char count.
	jmp gtchr8
gtchr5:	ora e			; Turn on the parity bit.
	cpi ('Z'-100O)		; Is it a ^Z?
	jnz gtchr7		; If not just proceed.
	lda eoflag		; EOF flag set?
	cpi 0
	jz gtchr6		; If not just go on.
	lda cpmflg		; Was the file created by CPM?
	cpi 0
	jnz gtch52		; If so, don't check for multiple ^Z's.
	lhld bufpnt
	lda chrcnt
	mov d,a			; Get the number of chars left in the DMA.
gtch51:	dcr d
	mov a,d
	jp gtch53		; Any chars left?
gtch52:	mvi a,0			; If not, get a zero.
	sta chrcnt		; Say no more chars in buffer.
	mov a,b			; Return the count in A.
	jmp rskp
gtch53:	mov a,m			; Get the next char.
	inx h			; Move the pointer.
	cpi ('Z'-100O)		; Is it a ^Z?
	jz gtch51		; If so see if they rest are.

gtchr6:	mvi a,('Z'-100O)	; Restore the ^Z.
gtchr7:	sta temp2		; Save the char.
	lxi h,temp1		; Point to the char total remaining.
	dcr m			; Decrement it.
	lhld cbfptr		; Position in character buffer.
	mov m,c			; Put the quote in the buffer.
	inx h
	shld cbfptr
	inr b			; Increment the char count.
	lda temp2		; Get the control char back.
	adi 40H			; Make the non-control.
	ani 7fH			; Modulo 200 octal.
gtchr8:	lhld cbfptr		; Position in character buffer.
	ora e			; Or in the parity bit.
	mov m,a			; Put the char in the buffer.
	inx h
	shld cbfptr
	inr b			; Increment the char count.
	jmp gtchr1		; Go around again.

gtceof:	mvi a,0FFH		; Get a minus one.
	ret

inbuf:	lda eoflag		; Have we reached the end?
	cpi 0
	rnz			; Return if set.
	push b			; Save the ACs.
	push d
	push h
	lxi h,chrcnt		; Reset character count.
	lda filflg		; Get the file flag.
	cpi 0			; Has there ever been anything in the DMA?
	jz inbuf1		; If so just set it.
	mvi m,bufsiz		; If not set it the buffer size.
	mvi a,0			; Zero the flag.
	sta filflg
	jmp inbuf2
inbuf1:	mvi m,bufsiz-1		; ELse set it to one less than the buffer size.
inbuf2:	lxi h,buff		; Set the buffer pointer.
	shld bufpnt
	mvi c,readf		; Read a record.
	lxi d,fcb
	call bdos
	pop h			; Restore ACs.
	pop d
	pop b
	lda filerc		; Get the file record count.
	sui 1			; Decrement it.
	sta filerc
	jnz rskp		; If not the last packet then retskp.
	lda fileex		; Any more left?
	cpi 0
	jz inbuf3
	sui 1
	sta fileex
	mvi a,80H		; Get a 128.
	sta filerc		; Start the record count over.
	jmp rskp
inbuf3:	mvi a,0FFH
	sta eoflag		; Set the EOF flag.
	jmp rskp

;	Get the next file spec.

gtnfil:	lda fcbnum		; Get the fcb number.
	sui 1
	rm
	sta fcbnum
	lxi h,fcbblk		; Get the base address of the list.
	rlc			; Compute the offset.
	rlc
	rlc
	rlc
	mov c,a			; Add it to the base of the list.
	mvi b,0
	dad b
	shld bufpnt
	lxi h,fcb
	shld fcbptr
	mvi b,0
gtnfl1:	lhld bufpnt		; Get next char.
	mov a,m
	inx h
	shld bufpnt
	lhld fcbptr		; Put the char in the FCB.
	mov m,a
	inx h
	shld fcbptr
	inr b
	mov a,b
	cpi 10H			; Done?
	jm gtnfl1
getfil:	mvi c,cflsz		; Get the file size.
	lxi d,fcb
	call bdos
	lda fcb+21H		; Get R0.
	cpi 0
	jm gtnfl2		; Is the last bit set?
	mvi b,0			; If not, we'll or in zero.
	jmp gtnfl3
gtnfl2:	mvi b,1			; If so, we'll or in one.
gtnfl3:	ani 7FH
	sta filerc		; Save as the file record count.
	lda fcb+22H		; Get R1.
	rlc			; Shift over one bit.
	ora b			; Or in the high order from R0.
	sta fileex		; Save it as the file extent.
	mvi a,0FFH
	sta filflg		; Nothing in the DMA.
	mvi a,0
	sta eoflag		; Not the end of file.
	sta fcb+0CH		; Zero the extent.
	sta fcb+0EH		; Must be zero for MAKEF or OPENF.
	sta fcb+20H		; Zero the current record.
	mvi c,openf		; Open the file.
	lxi d,fcb
	call bdos
	jmp rskp

;	Get the file name (including host to micro translation)

gofil:	lxi h,data		; Get the address of the file name.
	shld datptr		; Store the address.
	lxi h,fcb+1		; Address of the FCB.
	shld fcbptr		; Save it.
	mvi a,0
	sta temp1		; Initialize the char count.
	sta temp2
	sta fcb			; Set the drive to default to current.
	mvi b,' '
gofil1:	mov m,b			; Blank the FCB.
	inx h
	inr a
	cpi 0CH			; Twelve?
	jm gofil1
gofil2:	lhld datptr		; Get the NAME field.
	mov a,m
	inx h
	shld datptr
	cpi '.'			; Seperator?
	jnz gofil3
	lxi h,fcb+9H
	shld fcbptr
	lda temp1
	sta temp2
	mvi a,9H
	sta temp1
	jmp gofil6
gofil3:	cpi 0			; Trailing null?
	jz gofil7		; Then we're done.
	lhld fcbptr
	mov m,a
	inx h
	shld fcbptr
	lda temp1		; Get the char count.
	inr a
	sta temp1
	cpi 8H			; Are we finished with this field?
	jm gofil2
gofil4:	sta temp2
	lhld datptr
	mov a,m
	inx h
	shld datptr
	cpi 0
	jz gofil7
	cpi '.'			; Is this the terminator?
	jnz gofil4		; Go until we find it.
gofil6:	lhld datptr		; Get the TYPE field.
	mov a,m
	inx h
	shld datptr
	cpi 0			; Trailing null?
	jz gofil7		; Then we're done.
	lhld fcbptr
	mov m,a
	inx h
	shld fcbptr
	lda temp1		; Get the char count.
	inr a
	sta temp1
	cpi 0CH			; Are we finished with this field?
	jm gofil6
gofil7:	lhld datptr
	mvi m,'$'		; Put in a dollar sign for printing.
	mvi c,prstr		; Position cursor.
	lxi d,scrfln
	call bdos
	mvi c,prstr		; Print the file name.
	lxi d,data
	call bdos
	lda flwflg		; Is file warning on?
	cpi 0
	jz gofil9		; If not, just proceed.
	mvi c,openf		; See if the file exists.
	lxi d,fcb
	call bdos
	cpi 0FFH		; Does it exist?
	jz gofil9		; If not create it.
	lxi d,infms5
	call error3
	lda temp2		; Get the number of chars in the file name.
	cpi 0
	jnz gofil8
	lda temp1
	sta temp2
gofil8:	mvi b,0
	mov d,b			;[UTK2] Zero d for dad index into filename
	inr e
	mov e,a
	cpi 9H			; Is the first field full?
	jnz gofl81
	mvi b,0FFH		; Set a flag saying so.
	dcr e
gofl81:	lxi h,fcb		; Get the FCB.
	dad d			; Add in the character number.
	mvi m,'&'		; Replace the char with an ampersand.
	push b
	push d
	mvi c,openf		; See if the file exists.
	lxi d,fcb
	call bdos
	pop d
	pop b
	cpi 0FFH		; Does it exist?
	jz gofl89		; If not create it.
	mov a,b			; Get the flag.
	cpi 0
	jz gofl83
	dcr e			; Decrement the number of chars.
	mov a,e
	cpi 0
	jz gofl88		; If no more, die.
	jmp gofl81
gofl83:	inr e			; Increment the number of chars.
	mov a,e
	cpi 9H			; Are we to the end?
	jm gofl81		; If not try again.
	jz gofl88		;[UTK2] If yes, quit trying.
	lda temp2		; Get the original size.
	mov e,a
	jmp gofl81
	
gofl88:	mvi c,prstr		; Tell the user that we can't rename it.
	lxi d,erms16
	call bdos
	ret

gofl89:	lxi h,fcb+0CH		; Point past the end of the file name.
	mov b,m			; Save the present contents.
	mvi m,'$'		; Put in a dollar sign.
	push b
	mvi c,prstr		; Print the file name.
	lxi d,fcb+1
	call bdos
	pop b
	lxi h,fcb+0CH		; Restore over the dollar sign.
	mov m,b
gofil9:	mvi c,delf		; Delete the file if it exists.
	lxi d,fcb
	call bdos
	mvi a,0
	sta fcb+0CH		; Zero the extent.
	sta fcb+0EH		; Must be zero for MAKEF or OPENF.
	sta fcb+20H		; Zero the current record.
	mvi c,makef		; Now create it.
	lxi d,fcb
	call bdos
	cpi 0FFH		; Is the disk full?
	jnz rskp
	lxi d,erms11
	call error3
	ret

;	Packet routines

; Send_Packet
; This routine assembles a packet from the arguments given and sends it
; to the host.
;
; Expects the following:
;	A        - Type of packet (D,Y,N,S,R,E,F,Z,T)
;	ARGBLK   - Packet sequence number
;	ARGBLK+1 - Number of data characters
; Returns: +1 on failure
;	   +2 on success

spack:	sta argblk+2
	mvi b,0			; Zero the checksum AC.	
	lxi h,packet		; Get address of the send packet.
	mvi a,soh		; Get the start of header char.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	lda argblk+1		; Get the number of data chars.
	adi ' '+3		; Real packet character count made printable.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	mov b,a			; Start the checksum. 
	lda argblk		; Get the packet number.
	adi ' '			; Add a space so the number is printable.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	add b
	mov b,a			; Add the packet number to the checksum.
	lda argblk+2		; Get the packet type.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	add b
	mov b,a			; Add the type to the checksum.
spack2:	lda argblk+1		; Get the packet size.
	cpi 0			; Are there any chars of data?
	 jz spack3		;  No, finish up.
	dcr a			; Decrement the char count.
	sta argblk+1		; Put it back.
	mov a,m			; Get the next char.
	inx h			; Point to next char.
	add b
	mov b,a			; Add the char to the checksum.
	jmp spack2		; Go try again.
spack3:	mov a,b			; Get the character total.
	ani 0C0H		; Turn off all but the two high order bits.
	rrc
	rrc
	rrc
	rrc
	rrc
	rrc			; Shift them into the low order position.
	add b			; Add it to the old bits.
	ani 3FH			; Turn off the two high order bits.  (MOD 64)
	adi ' '			; Add a space so the number is printable.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	lda seol		; Get the EOL the other host wants.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	mvi a,0			; Get a null.
	mov m,a			; Put in the packet.
IF debug
	inx h			; Point to next char.
	mvi a,'$'		; Get a dollar sign.
	mov m,a			; Put in the packet.
ENDIF				;debug
	call outpkt		; Call the system dependent routine.
	 jmp r
	jmp rskp

;	Write out a packet.

outpkt:	lda spad		; Get the number of padding chars.
	sta temp1
outpk2:	lda temp1		; Get the count.
	dcr a
	cpi 0
	jm outpk6		; If none left proceed.
	sta temp1
	lda spadch		; Get the padding char.
	mov e,a			; Put the char in right AC.
	call outchr		; Output it.
	jmp outpk2
outpk6:	lda ibmflg		; Is this the (dumb) IBM.
	cpi 0
	jz outpk8		; If not then proceed.
	lda state		; Check if this is the Send-Init packet.
	cpi 'S'
;* This will also have to be taken care for 'R' (receive), 'G' (generic)
;* and 'C' (command) packets if the IBM becomes a server.
	jz outpk8		; If so don't wait for the XON.
outpk7:	call inchr		; Wait for the turn around char.
	 jmp outpk8
	cpi xon			; Is it the IBM turn around character?
	jnz outpk7		; If not, go until it is.
outpk8:
IF debug
	mvi c,prstr		; Print the packet
	lxi d,sppos
	call bdos
	lxi d,packet+1
	mvi c,prstr
	call bdos
ENDIF				;debug

	lxi h,packet		; Point to the packet.
outlup:	mov a,m			; Get the next character.
	cpi 0			; Is it a null?
	jz rskp			; If so return success.
	mov e,a			; Put the char in right AC.
	call outchr		; Output the character.
	inx h			; Increment the char pointer.
	jmp outlup

; Set the parity for a character in A.

setpar:	push h			; Save HL.
	push b
	lxi h,parity
	mov c,m			; Get the parity routine.
	mvi b,0
	lxi h,parjmp		; Get the first address.
	dad b
	pchl

parjmp:	jmp even
	jmp mark
	jmp none
	jmp odd
	jmp space

none:	jmp parret		; Don't touch the parity bit.

even:	ani 7FH			; Strip parity.
	jpe parret		; Already even, leave it.
	ori 80H			; Make it even parity.
	jmp parret

mark:	ori 80H			; Turn on the parity bit.
	jmp parret

odd:	ani 7FH			; Strip parity.
	jpo parret		; Already odd, leave it.
	ori 80H			; Make it odd parity.
	jmp parret

space:	ani 7FH			; Turn off the parity bit.
	jmp parret

parret:	pop b
	pop h			; Restore HL.
	ret

;************************System Dependent****************************
;	Put a char in E to the port.

IF osi OR apple
outchr:	push h
outch2: lxi h,mnprts		; Get the port status into A.
	mov a,m
	ani output		; Loop till ready.
	jz outch2
	mov a,e
	call setpar
	lxi h,mnport		; Write the character.
	mov m,a
	pop h
	ret
ENDIF ; osi OR apple

IF osbrn1
outchr:	call	osldst	; Read the status port
	ani	output	; Loop till ready.
	jz	outchr
	mov	a,e
	call	setpar	; What about Bit 7?
	jmp	osstda	; Write to the data port
ENDIF ; osbrn1

IF brain OR vector OR heath OR z100 OR trs80 OR telcon
outchr:	in mnprts		; Get the output ready flag.
	ani output		; Is it set?
	jz outchr		; If so, loop until it isn't.
	mov a,e
	call setpar
	out mnport		; Output it.
	ret
ENDIF ; brain OR vector OR heath OR z100 OR trs80 OR telcon

IF gener OR rainbo OR robin OR dmII
outchr:	push h
	push b
	mov a,e
	call setpar
	mov e,a			; Put the char in E.
	mvi c,punout		; Out put to the punch.
	call bdos
	pop b
	pop h
	ret
ENDIF				;gener OR robin OR rainbo OR dmII

;************************System Dependent****************************
;
;	Get a char from the port and return in A.

IF osi OR apple
inchr:	lda mnprts		; Get port status into A.
ENDIF ; osi OR apple

IF osbrn1
inchr:	call osldst
ENDIF ; osbrn1

IF osi OR apple OR osbrn1
	ani input		; See if the input ready bit is on.
	jnz inchr2		; If so go read the input.
	mvi c,consta		; Is a char on the console?
	call bdos
	cpi 0
	jz inchr		; If not go look for another char.
	mvi c,conin		; Get the char.
	call bdos
	cpi cr			; Is it a carriage return?
	jnz inchr		; If not go look for another char.
	ret
ENDIF ; osi OR apple OR osbrn1

IF osi OR apple
inchr2:	lxi h,mnport		; If so, get the char.
	mov b,m
ENDIF ;  osi OR apple

IF osbrn1
inchr2:	CALL	OSLDDA	; Read the data port
	mov b,a
ENDIF ; osbrn1

IF osi OR apple OR osbrn1
	lda parity		; Is the parity none?
	cpi parnon
	mov a,b
	jz rskp			; If so just return.
	ani 7FH			; Turn off the parity bit.
	jmp rskp
ENDIF ; osi OR apple OR osbrn1

IF brain OR vector OR heath OR z100 OR trs80 OR telcon
inchr:	in mnprts		; Get the port status into A.
	ani input		; See if the input ready bit is on.
	jnz inchr2		; If so go read the input.
	mvi c,consta		; Is a char on the console?
	call bdos
	cpi 0
	jz inchr		; If not go look for another char.
	mvi c,conin		; Get the char.
	call bdos
	cpi cr			; Is it a carriage return?
	jnz inchr		; If not go look for another char.
	ret
inchr2:	in mnport		; If so, get the char.
	mov b,a
	lda parity		; Is the parity none?
	cpi parnon
	mov a,b
	jz rskp			; If so just return.
	ani 7FH			; Turn off the parity bit.
	jmp rskp
ENDIF ; brain OR vector OR heath OR z100 or trs80 OR telcon

IF gener OR rainbo OR robin OR dmII
inchr:	push h
	push b
inchr2:	mvi e,batio		;switch I/O byte
	mvi c,ptiob
	call bdos
	call bconst		;see if char at COMM-Port
	cpi 0			;
	jnz inchr3		;we have one
	mvi e,defio		;switch back to normal
	mvi c,ptiob		;we have to check for keyboard input
	call bdos
	call bconst		;see if char from keyboard
	cpi 0
	jz inchr2		;nothing, check COMM-Port
	call bconin		;get Keyboard-Input
	cpi cr			;Carriage return?
	jnz inchr2		;take only Carriage returns
	pop b
	pop h
	ret
inchr3:	call bconin		; we got a char at COMM-Port
	mov b,a
	lda parity		;is the parity none?
	cpi parnon
	mov a,b
	push a
	mvi e,defio		;switch back to normal
	mvi c,ptiob		;we have to check for keyboard input
	call bdos
	pop a
	pop b
	pop h
	jz rskp			;return, we have COMM-Character
	ani 7FH			;strip Parity bit
	jmp rskp		;and return, we have COMM-Character
ENDIF				;gener OR rainbo OR robin OR dmII

; Receive_Packet
; This routine waits for a packet to arrive from the host.  It reads
; characters until it finds a SOH.  It then reads the packet into packet.
;
; Returns:  +1 failure (if the checksum is wrong or the packet trashed)
;	    +2 success with A        - message type
;			    ARGBLK   - message number
;                           ARGBLK+1 - length of data

rpack:	call inpkt		; Read up to a carriage return.
	 jmp r			;  Return bad.
rpack0:	call getchr		; Get a character.
	 jmp rpack		;  Hit a CR; null line; just start over.
	cpi soh			; Is the char the start of header char?
	 jnz rpack0		;  No, go until it is.
rpack1:	call getchr		; Get a character.
	 jmp r			;  Hit the carriage return, return bad.
	cpi soh			; Is the char the start of header char?
	 jz rpack1		;  Yes, then go start over.
	mov b,a			; Start the checksum.
	sui ' '+3		; Get the real data count.
	sta argblk+1
	call getchr		; Get a character.
	 jmp r			;  Hit the carriage return, return bad.
	cpi soh			; Is the char the start of header char?
	 jz rpack1		;  Yes, then go start over.
	sta argblk
	add b			; Add it to the checksum.
	mov b,a
	lda argblk
	sui ' '			; Get the real packet number.
	sta argblk
	call getchr		; Get a character.
	 jmp r			;  Hit the carriage return, return bad.
	cpi soh			; Is the char the start of header char?
	 jz rpack1		;  Yes, then go start over.
	sta temp1		; Save the message type.
	add b			; Add it to the checksum.
	mov b,a
	lda argblk+1		; Get the number of data characters.
	sta temp2
	lxi h,data		; Point to the data buffer.
	shld datptr
rpack2:	lda temp2
	sui 1			; Any data characters?
	 jm rpack3		;  If not go get the checksum.
	sta temp2
	call getchr		; Get a character.
	 jmp r			;  Hit the carriage return, return bad.
	cpi soh			; Is the char the start of header char?
	 jz rpack1		;  Yes, then go start over.
	lhld datptr
	mov m,a			; Put the char into the packet.
	inx h			; Point to the next character.
	shld datptr
	add b			; Add it to the checksum.
	mov b,a
	jmp rpack2		; Go get another.
rpack3:	call getchr		; Get a character.
	 jmp r			;  Hit the carriage return, return bad.
	cpi soh			; Is the char the start of header char?
	 jz rpack1		;  Yes, then go start over.
	sui ' '			; Turn the char back into a number.
	sta temp3
	mov a,b			; Get the character total.
	ani 0C0H		; Turn off all but the two high order bits.
	rrc
	rrc
	rrc
	rrc
	rrc
	rrc			; Shift them into the low order position.
	add b			; Add it to the old bits.
	ani 3FH			; Turn off the two high order bits.  (MOD 64)
	mov b,a
	lda temp3		; Get the real received checksum.
	cmp b			; Are they equal?
	jz rpack4		; If so, proceed.
	call updrtr		; If not, update the number of retries.
	ret			; Return error.

rpack4:	lhld datptr
	mvi m,0			; Put a null at the end of the data.
	lda temp1		; Get the type.
	jmp rskp

inpkt:	lxi h,recpkt		; Point to the beginning of the packet.
	shld pktptr
inpkt2:	call inchr		; Get a character.
	 jmp r			;  Return failure.
	lhld pktptr
	mov m,a			; Put the char in the packet.
	inx h
	shld pktptr
	mov b,a
	lda reol		; Get the EOL char.
	cmp b
	jnz inpkt2		; If not loop for another.
IF debug
	mvi a,'$'		; Get a dollar sign.
	mov m,a			; Put in the packet.
	inx h			; Point to next char.
	lxi d,rppos		; Print the packet
	mvi c,prstr
	call bdos
	lxi d,recpkt+1
	mvi c,prstr
	call bdos
ENDIF				;debug
	lxi h,recpkt
	shld pktptr		; Save the packet pointer.
	jmp rskp		; If so we are done.


getchr:	lhld pktptr		; Get the packet pointer.
	mov a,m			; Get the char.
	inx h
	shld pktptr
	cpi cr			; Is it the carriage return?
	jnz rskp		; If not return retskp.
	ret			; If so return failure.

; This is where we go if we get an error during a protocol communication.
;   Call error prints the error packet on line 6 or so.
;   Call error1 print CRLF followed by the error packet.
;   Call error2 just prints the error packet.
;   Call error3 positions cursor and prints error message specified in DE.

error:	call error9		; Position the cursor.
	mvi a,'A'		; Set the state to abort.
	sta state
	jmp error2

error1:	mvi c,prstr
	lxi d,crlf		; Print a CRLF.
	call bdos
error2:	lda argblk+1		; Get the length of the data.
	mov c,a
	mvi b,0			; Put it into BC
	lxi h,data		; Get the address of the data.
	dad b			; Get to the end of the string.
	mvi a,'$'		; Put a dollar sign at the end.
	mov m,a
	mvi c,prstr		; Print the error message.
	lxi d,data
	call bdos
	ret
error3:	push d			; Save the pointer to the message.
	call error9		; Position the cursor.
	mvi c,prstr		; Clear the line.
	lxi d,clrlin
	call bdos
	pop d			; Get the pointer back.
	mvi c,prstr		; Print the error message.
	call bdos
	ret

error9:	mvi c,prstr		; Position the cursor.
	lxi d,screrr
	call bdos
	ret

finmes:	push d			; Save message.
	mvi c,prstr		; Position the cursor.
	lxi d,scrst
	call bdos
	mvi c,prstr		; Print the termination message.
	pop d
	call bdos
	mvi c,prstr		; Position the cursor for the prompt.
	lxi d,scrend
	call bdos
	ret


; This is the FINISH command.  It tells the remote KERSRV to exit.

finish:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	mvi a,0
	sta numtry		; Inititialize count.

finsh1:	lda numtry		; How many times have we tried?
	cpi maxtry		; Too many times?
	jm finsh3		; No, try it.
finsh2:	lxi d,erms18		; Say we couldn't do it.
	mvi c,prstr
	call bdos
	jmp kermit		; Go home.
finsh3:	inr a			; Increment the number of tries.
	sta numtry
	mvi a,0
	sta argblk		; Make it packet number zero.
	mvi a,1
	sta argblk+1		; One piece of data.
	lxi h,data
	mvi m,'F'		; Finish running Kermit.
	mvi a,'G'		; Generic command packet.
	call spack
	 jmp finsh2		;  Tell the user and die.
	call rpack		; Get an acknowledgement.
	 jmp finsh1		;  Go try again.
	cpi 'Y'			; ACK?
	jz kermit		; Yes, we are done.
	cpi 'E'			; Is it an error packet?
	jnz finsh1		; Try sending the packet again.
	call error1		; Print the error message.
	jmp kermit

; This is the LOGOUT command.  It tells the remote KERSRV to logout.

logout:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	call logo		; Send the logout packet.
	jmp kermit		; Go get another command
	jmp kermit		;  whether we succeed or not.

logo:	mvi a,0
	sta numtry		; Inititialize count.

logo1:	lda numtry		; How many times have we tried?
	cpi maxtry		; Too many times?
	jm logo3		; No, try it.
logo2:	lxi d,erms19		; Say we couldn't do it.
	mvi c,prstr
	call bdos
	ret			; Finished.
logo3:	inr a			; Increment the number of tries.
	sta numtry
	mvi a,0
	sta argblk		; Make it packet number zero.
	mvi a,1
	sta argblk+1		; One piece of data.
	lxi h,data
	mvi m,'L'		; Logout the remote host.
	mvi a,'G'		; Generic command packet.
	call spack
	 jmp logo2		;  Tell the user and die.
	call rpack		; Get an acknowledgement
	 jmp logo1		;  Go try again.
	cpi 'Y'			; ACK?
	jz rskp			; Yes, we are done.
	cpi 'E'			; Is it an error packet?
	jnz logo1		; Try sending the packet again.
	call error1		; Print the error message.
	ret			; All done.

; This is the BYE command.  It tells the remote KERSRV to logout and exits.

bye:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	call logo		; Tell the main frame to logout.
	jmp kermit		; If it fails, don't exit.
IF apple
	mvi a,0			; Hangup our end too!
	sta mnmodm
ENDIF ; apple
	jmp exit1		; Exit Kermit.

; This is the 'exit' command.  It leaves KERMIT and returns to CP/M.

exit:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.

exit1:	lhld oldsp		; Get back the system stack
	sphl			; and restore it.
	ret			; Then return to system.

; This is the log command.  It logs a session to a file.

log:	mvi a,cmofi		; Parse an input file spec.
	lxi d,fcb
	call comnd		
	 jmp kermt3
	mvi a,cmcfm		; Parse a confirm.
	call comnd
	 jmp kermt3
	lxi h,logflg
	mvi m,0FFH		; Set the log flag.
	lxi h,buff
	shld bufpnt
	mvi c,delf		; Delete the file if it exists.
	lxi d,fcb
	call bdos
	mvi a,0
	sta fcb+0CH		; Zero the extent.
	sta fcb+0EH		; Must be zero for MAKEF or OPENF.
	sta fcb+20H		; Zero the current record.
	mvi c,makef		; Now create it.
	lxi d,fcb
	call bdos
	cpi 0FFH		; Is the disk full?
	jnz kermit		;[UTK3]
	mvi c,prstr		; If so tell the user.
	lxi d,erms17
	call bdos
	jmp kermit

; This is the 'help' command.  It gives a list of the commands.

help:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
help2:	mvi c,prstr		; Print a string to the console.
	lxi d,tophlp		; The address of the help message.
	call bdos
	jmp kermit

;	This is the CONNECT command.

telnet:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.

IF apple
	call ckdial		; See if dialing is required.
	 jmp kermit		;  Go to command loop if aborted.
ENDIF ; apple

	mvi c,prstr		; Output start of message.
	lxi d,infms7
	call bdos
	call escpr		; Print the escape char.
	mvi c,prstr		; Output the rest of the message.
	lxi d,infms8
	call bdos

IF apple
	call ckdial		; See if dialing is required.
	 jmp kermit		;  Go to command loop if aborted.
ENDIF				;apple

chrlup:	call prtchr		; See if char at port (type to cons).
	call conchr		; See if char at cons (type to port).
	 jmp kermit		;  Go to command loop.
	jmp chrlup		; Go do it again.


;************************System Dependent****************************
IF gener OR rainbo OR robin OR dmII
prtchr:	mvi e,batio		;Set I/O byte to CON=BAT
	mvi c,ptiob
	call bdos
prtchx:	call bconst		; Is Char at COMM-Port?
	cpi 0			;something there?
	jnz prtret		;Something there, get char
	mvi e,defio		;Set I/O byte to CON=CRT
	mvi c,ptiob
	call bdos
	ret
prtret:	call bconin		; Read COMM-PORT
	ani 7FH			;strip Bit 8
	mov c,a			;call BIOS direct w character in C
	call bcnout		;Echo COMM-Character on screen (in C)
				; and fall into "normal " code
ENDIF				;gener or rainbo OR robin OR dmII

IF osi OR apple
prtchr:	lda mnprts		; Get the port status into A.
	ani input		; See if the input ready bit is on.
	rz			; If not then return.
prtch2:	lda mnport		; If so, get the char.
ENDIF ; osi OR apple

IF osbrn1
prtchr:	CALL	OSLDST		; Read the status port
	ani input
	rz
prtch2:	CALL	OSLDDA		; read the data port
ENDIF

IF brain OR vector OR heath OR z100 OR trs80 OR telcon
prtchr:	in mnprts		; Get the port status into A.
	ani input		; See if the input ready bit is on.
	rz			; If not then return.
prtch2:	in mnport		; If so, get the char.
ENDIF ; brain OR vector OR heath OR z100 OR trs80 OR telcon

	ani 7FH			; Make seven bit. 
	mov e,a			; Set the char aside.

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
	lda vtflg		; Get the VT52 emulation flag.
	cpi 0			; Is the flag set?
	jz prtch1		; If not, don't do this stuff.
ENDIF				;NOT (robin OR rainbo OR gener OR dmII OR osi)

IF vector
	lda vtvflg		; Get the vector cursor control flag.
	cpi 0
	jnz vtvect		; If its not zero go process the char.
ENDIF				;vector

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
	lda escflg		; Get the escape flag.
	cpi 0			; Is the flag set?
	jnz vt52		; If so go translate the sequence.
	mov a,e			; Get the char for testing.
	cpi del			; Is the char a delete.
	rz			; If so then forget this foolishness.
	cpi esc			; Is the char an escape?
	jnz prtch1		; If not skip on.
	mvi a,1			; Get a one.
	sta escflg		; Set the escape flag.
	jmp prtchr		; Get another char...
ENDIF ; NOT (robin OR rainbo OR gener OR dmII OR osi)

prtch1:	lda logflg		; Get the log flag.
	cpi 0
	cnz logit		; Log the char if it is set.

IF NOT (robin OR rainbo OR gener OR dmII)
	mvi c,dconio		; Console output bdos call.
	call bdos		; Output the char to the console.
	jmp prtchr		; Go see if there is another character.
ENDIF				;NOT (robin OR rainbo OR gener OR dmII)

IF (robin OR rainbo OR gener OR dmII)
	mov c,e			; Character
	call bcnout		; to Console
	jmp prtchx		; and back for more
ENDIF				; (robin OR rainbo OR gener OR dmII)


conchr:	mvi c,dconio		; Direct console I/O BDOS call.
	mvi e,0FFH		; Input.
	call BDOS
	cpi 0			; Is it a null?
	jz rskp			; If so, don't bother to write it.
	mov e,a			; Move the char for comparison.
	lda escchr		; Get the escape char.
	cmp e			; Is it an escape char?
	jz intchr		; If so go process it.
	mov a,e			; Get the char.
	call setpar		; Set parity (if any).
	mov e,a			; Restore it.
	call prtout		; Output the char to the port.
	lda ecoflg		; Get the echo flag.
	cpi 0			; Is it turned on?
	jz rskp			; If not we're done here.
	mov a,e			; Get the char.
	ani 7FH			; Turn off the parity bit.
	mov e,a			; Return it.
	mvi c,dconio		; Direct console output.
	call bdos		; Echo the char.
	jmp rskp

intchr:	mvi c,dconio		; Direct console I/O.
	mvi e,0FFH		; Input.
	call bdos		; Get a char.
	cpi 0			; Is the char a null?
	jz intchr		; If so, go until we get a char.
	mov b,a			; Save the actual char.
	cpi ctrlc		;is it Control-C?
	jz contc		;yes
	ani 137O		; Convert to upper case.
	cpi 'C'			; Is it close?
	jnz intch0		; If not proceed.
contc:	mvi c,prstr		; Say we are back.
	lxi d,infms9
	call bdos
	lda logflg		; Get the log flag.
	cpi 0			; Is it set?
	rz			; Return if it is zero.
	mvi a,0
	sta logflg		; Turn off the log flag.
	mvi c,prstr		; Tell the user we are closing the file.
	lxi d,infms6
	call bdos
	lhld bufpnt
	mvi m,('Z'-100O)	; Put in a ^Z.
	mvi c,writef		; Write the last buffer.
	lxi d,fcb
	call bdos
	mvi c,closf		; Close the file.
	lxi d,fcb
	call bdos
	ret

IF apple
intch0:	cpi 'D'			;Disconnect Modem?
	jnz apintc
	mvi a,0			;Hangup the modem
	sta mnmodm
	ret
apintc:	cpi 'S'			; Is it status?
ENDIF				;apple

IF NOT apple
intch0:	cpi 'S'			; Is it status?
ENDIF				;NOT apple

	jnz inch01		; If not, proceed.
	call stat01		; Print out the status stuff.
	jmp rskp

inch01:	mov a,b			; Get the char.
	cpi '?'			; Is it help?
	jnz intch1		; If not, go to the next check. 
	lxi d,inthlp		; If so, get the address of the help message.
	mvi c,prstr		; Print it.
	call bdos
	jmp intchr		; Get another char.

intch1:	mov e,a			; Put the char into another reg.
	lda escchr		; Get the escape char.
	cmp e			; Is it the escape char?
	jnz intch2		; If not, go send a beep to the user.
	mov a,e			; Get the char.
	call setpar
	mov e,a			; Restore it.
	call prtout		; Output it.
	jmp rskp		; Return, we are done here.
intch2:	mvi e,'G'-100O		; Otherwise send a beep.
	mvi c,dconio
	call bdos
	jmp rskp

IF apple
; This code was mostly taken from
;	APMODEM.ASM V2.1
;	Based on MODEM.ASM by Ward Christensen
;	Modified for the Apple ][ by Gordon Banks 1-Jan-81
;	Micromodem ][ dialer option by Dav Holle  2-Feb-81
;	Code modified for KERMIT by Scott Robinson 14-Oct-82
;
; Come here to see if we need to dial a number.
;
ckdial:	lda	mnport		;access the data port
	lda	mnprts		;check status
	ani	4		;do we already have carrier?
	jz	rskp		; Yes, just continue
	mvi	a,0		;Hangup Phone for starters
	sta	mnmodm
	lxi	b,1000		;Delay for a second
	call	delay
	mvi	a,8FH		;orgmod+ap300+apoffh
	sta	holdd		; storing mode for after dialing
	mvi	A,8DH		;Go Offhook to start dialing sequence
	sta	mnmodm
	mvi	a,apinc1	;Init ACIA
	sta	mnport
	mvi	a,apinc2	;Set ACIA bits per character
	sta	mnport

	lxi	b,2500		;wait 2.5 seconds for dial tone
	call	delay
	lxi	d,dialms	;Ask the user for the number
	mvi	c,prstr
	call	bdos
;
gtdial: mvi	c,conin		;Get a character
	call	bdos
	push	psw		;save it
	cpi	30H		;is it big enough to dial?
	jc	dialed		;  no
	cpi	3AH		;is it too big to dial?
	jnc	dialed		;  yes
	ani	0FH		;ok, it's a digit, get its value
	jnz	dialnz		;dial nonzero digits as-is
	mvi	A,10		;dial zero as ten
;
dialnz:	mov	e,a		;count pulses in E-reg
dopuls: mvi	a,0DH		;put it on-hook
	sta	mnmodm
	LXI	B,61	;61-millisec pulse
	CALL	DELAY
	MVI	A,8DH	;take it off-hook again...
	STA	mnmodm
	LXI	B,39	;39-millisec delay between pulses
	CALL	DELAY
	DCR	E	;any more pulses to do?
	JNZ	dopuls ;  yep, do 'em
	LXI	B,600	;delay 600 msecs between digits
	CALL	DELAY
;
DIALED:	POP	PSW	;get back the char
	CPI	CR	;do we have a CR (done dialing)?
	JNZ	gtdial ;  no, keep on dialin'
	lxi	d,dialm2
	mvi	c,prstr
	call	bdos

tictoc: mvi	c,dconio ;Direct console input.
	mvi	e,0FFH
	call	BDOS
	cpi	 0	; Have a charcter?
	jnz 	nodial	; If so we abort
	LDA	mnport 	;access the data port
	LDA	mnprts ;get modem status
	ANI	4	;carrier?
	JNZ	tictoc		;No
;
	LDA	HOLDD	;get the old modem control byte
	STA	mnmodm ;turn our carrier on
	
	lxi	d,dialm3
	mvi	c,prstr
	call	bdos
	jmp	rskp
nodial: mvi	a,0		;Hangup the modem.
	sta	mnmodm
	ret			;Return to abort the command.
;
holdd:	db	0		;Modem setup code
dialms:	DB	'Number to Dial: $'
dialm2:	DB	CR,LF,'Awaiting Carrier....(any key aborts)$'
dialm3:	DB	cr,lf,'Connected.',CR,LF,'$'
;
; DELAY wait for the number of millisecs in B,C
;
DELAY:	PUSH	B	;save B,C
	PUSH	D	;save D,E
	INR	B	;bump B for later DCR
;
DELAY1:	MVI	E,126	;delay count for 1 millisec (Apple Z80 clock=2.041MHz)
;
DELAY2:	DCR	E	;count
	JNZ	DELAY2	;  down
;
	DCR	C	;more millisecs?
	JNZ	DELAY1	;  yes
	DCR	B	;no - more in hi byte?
	JNZ	DELAY1	;  yes
	POP	D	;  no,	restore D,E
	POP	B	;	restore B,C
	RET
ENDIF				;apple

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
vt52:	mvi a,00H		; Reset the ol' escape flag.
	sta escflg
	mov a,e			; Get the char.
ENDIF				;NOT (robin OR rainbo OR gener OR dmII OR osi)

IF vector
	cpi 'Y'			; Is it cursor position?
	jnz vt52a		; If so handle it special.
	mvi a,2
	sta vtvflg		; Save the flag saying so.
	mvi c,conout		; Output the escape.
	mvi e,esc
	call bdos
	ret
vt52a:
ENDIF				;vector

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
	cpi 'A'			; Less than an 'A'?
	jm vtig			; Yes - ignore.
	cpi 'K'+1		; Greater than 'K'?
	jp vtig			; Yes - ignore.
	sui 'A'			; Else make into index.
	rlc			; Multiply by four.
	rlc			; (Shift left twice.)
	lxi h,ttab		; Load base addr of table.
	mov e,a			; Move a into de pair.
	mvi d,00H		; Zero out high byte.
	dad d			; Double add index+offset.
	xchg 			; Exchange de with hl.
	mvi c,prstr		; Function code
	call bdos		; and syscall.
	ret			; Return.
ENDIF				;NOT (robin OR rainbo OR gener OR dmII OR osi)

IF vector
vtvect:				; Treat cursor control special.
	lda vtvflg		; Get the flag.
	cpi 02H			; Is this the first char?
	jnz vtvct2		; If not go write it.
	dcr a
	sta vtvflg		; Save the updated flag.
	mov a,e			; Get the char.
	sbi ' '-1		; Subtract a space to get a number.
	sta vctccc		; Save the vector cursor control char.
	ret
vtvct2:	dcr a
	sta vtvflg		; Save the updated flag.
	mov a,e			; Get the char.
	sbi ' '-1		; Subtract a space.
	mov e,a			; Move to output register.
	mvi c,dconio		; The function
	call bdos		; and the syscall.
	lda vctccc		; Get the first char.
	mov e,a
	mvi c,dconio		; Output it.
	call bdos
	ret			; Return home.
ENDIF				;vector

IF NOT (robin OR rainbo OR gener OR dmII)

vtig:				; Ignore escape sequence.
	push psw		; Push the char to be output.
	mvi e,esc		; Load an escape.
	mvi c,conout		; The function code
	call bdos		; and the syscal.
	pop psw			; Restore the character
	mov e,a			; and move to output register.
	mvi c,conout		; The function
	call bdos		; and the syscall.
	ret			; Return home.
ENDIF				;NOT (robin OR rainbo OR gener OR dmII)


logit:	lhld bufpnt
	mov m,e			; Store the char.
	inx h
	shld bufpnt
	mov a,l
	cpi 0			; Buffer full?
	rnz
	push d
	mvi e,xoff		;[UTK3] ^Q to stop the
	call prtout		;[UTK3] host until we
	mvi c,writef		; write out the buffer.
	lxi d,fcb
	call bdos
	cpi 0			; Successful.
	jz logit2
	mvi c,prstr		; Tell about it.
	lxi d,erms11
	call bdos
logit2:	mvi e,xon		;[UTK3] ^Q to restart
	call prtout		;[UTK3] the host.
	lxi h,buff
	shld bufpnt		; Reset the buffer pointer.
	pop d
	ret

; This is the SET command.

setcom:	lxi d,settab		; Parse a keyword from the set table.
	lxi h,sethlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	lxi h,setjtb		; Get the address of the jump table.
	mov c,a
	mvi b,0
	dad b
	pchl
setjtb:	jmp escape
	jmp ibmset
	jmp local
	jmp kermt3
	jmp setsnd
	jmp filwar
	jmp setcpm
	jmp parset

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
	jmp vt52em
ENDIF				;NOT (robin OR rainbo OR gener OR dmII OR osi)

IF brain OR osbrn1
	jmp baud
ENDIF				;brain OR robin OR osbrn1
;IF robin
;	jmp gppset
;ENDIF				;robin

; SET SEND command.

setsnd:	lxi d,stsntb		; Parse a keyword from the set send table.
	lxi h,stshlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	lxi h,stsjtb		; Get the address of the jump table.
	mov c,a
	mvi b,0
	dad b
	pchl
stsjtb:	jmp stpdch
	jmp stpad

stpad:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	jmp kermit

stpdch:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	jmp kermit

IF brain
;	This is the BAUD change SET subcommand.

baud:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lxi d,baudtb		; Get the address of the baud rate table.
	mvi c,prstr		; Output to the user.
	call bdos
	mvi c,conin		; Console input (with echo).
	call bdos
	ani 137O		; Capitalize the char.
	sui 'A'			; Normalize to zero.
	jm bderr		; Go tell the user he flubbed.
	cpi 10H			; Is the number greater than 15?
	jp bderr		; Go tell the user he flubbed.
	mov b,a			; Save the number.
	lda baudrt		; Get the present baud rates.
	mov d,a			; Set it aside.
	mov a,b			; Get the new baud rate.
	rlc			; Shift left 4 places.
	rlc
	rlc
	rlc
	mov b,a			; Set it aside.
	mov a,d			; Get the old baud rates.
	ani 0FH			; Turn off the left.
baud2:	add b			; Combine the two rates.
	sta baudrt		; Store the new baud rates.
	out baudst		; Set the baud rates.
	jmp kermit

bderr:	lxi d,ermes2		; Get the error message.
	mvi c,prstr		; Print it.
	call bdos
	jmp kermit
ENDIF				;brain

IF osbrn1
; The same command, this time for the Osborne 1

baud:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lxi d,baudtb		; Get the address of the baud rate table.
	mvi c,prstr		; Output to the user.
	call bdos
	mvi c,conin		; Console input (with echo).
	call bdos
	ani 137O		; Capitalize the char.
	cpi	'A'		; A means 300
	mvi	c,0		; and 0 means 300 in the baud byte
	jz	baud1
	cpi	'B'		; B means 1200
	jnz	bderr		; and anything else is wrong
	inr	c		; non-zero means 1200
baud1:	mov	a,c
	sta	osbaud		; Remember it.
	call	osbset		; Osborne setup routine
	jmp	kermit

bderr:	lxi d,ermes2		; Get the error message.
	mvi c,prstr		; Print it.
	call bdos
	jmp kermit

osbset:	mvi	a,OSBIN1	; Reset the ACIA
	CALL	OSSTST		; Write the control port
osbs1:	inr	c		; Waiting loop
	jnz	osbs1
	lda	osbaud		; Go for 300 or 1200?
	ora	a
	mvi	a,osbi03	; Guess 300
	jz	osbs2
	mvi	a,osbi12	; wrong: 1200
osbs2:	sta	baudrt		; (seems this is what one does on an Osborne)
	JMP	OSSTST		; Write the control reg.
ENDIF ; osbrn1

;	This is the ESCAPE character SET subcommand.

escape:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lxi d,escmes		; Get the address of the escape message.
	mvi c,prstr		; Print it.
	call bdos
	mvi c,conin		; Get the char.
	call bdos
	sta escchr		; Store the new escape character.
	jmp kermit

;	This is the LOCAL echo SET subcommand.

local:	lxi d,ontab
	lxi h,onhlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta ecoflg		; Set the local echo flag.
	jmp kermit

IF NOT (robin OR rainbo OR gener OR dmII OR osi)
;	This is the VT52 emulation SET subcommand.

vt52em:	lxi d,ontab
	lxi h,onhlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta vtflg		; Set the VT52 emulation flag.
	jmp kermit
ENDIF				;NOT (robin OR rainbo OR gener OR dmII OR osi)

; This is the FILE-WARNING SET subcommand

filwar:	lxi d,ontab
	lxi h,onhlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta flwflg		; Set the file-warning flag.
	jmp kermit

;	This is the SET IBM command.

ibmset:	lxi d,ontab
	lxi h,onhlp
	mvi a,cmkey
	call comnd
	 jmp kermt2
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta ibmflg		; Set the IBM flag.
	cpi 0			; Is it turned on?
	jz ibmst1		; If not, set parity to the default.
	mvi a,ibmpar		; Get the IBM parity.
	mvi b,1			; Set local echo on.
	jmp ibmst2
ibmst1:	mvi a,defpar
	mvi b,0			; Set local echo off.
ibmst2:	sta parity		; Save them.
	mov a,b
	sta ecoflg
	jmp kermit

;	This is the SET PORT command.
;IF robin
;
; Nick Bush's SET PORT command commented out for now, because it hasn't been
; worked into the generic scheme.
;
;gppset:lxi d,gpptab
;	lxi h,gpphlp
;	mvi a,cmkey
;	call comnd
;	 jmp kermt2
;	sta temp1		; Save the parsed value.
;	mvi a,cmcfm
;	call comnd		; Get a confirm.
;	 jmp kermt3		;  Didn't get a confirm.
;	lda temp1		; Get the parsed value.
;	sta gppflg		; Set the port flag.
;	jmp kermit
;ENDIF ; robin


;	SET CPM-CREATED-FILE command.

setcpm:	lxi d,ontab
	lxi h,onhlp
	mvi a,cmkey
	call comnd
	 jmp kermt3
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta cpmflg		; Set the CPM flag.
	jmp kermit

parset:	lxi d,partab
	lxi h,parhlp
	mvi a,cmkey
	call comnd
	 jmp kermt3
	sta temp1		; Save the parsed value.
	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
	lda temp1		; Get the parsed value.
	sta parity		; Set the CPM flag.
	jmp kermit

; This is the SHOW command.

show:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
;* Reconcile this and status.
	call stat01		; For now just cop out.
	jmp kermit

;	This is the STATUS command.

status:	call stat0
	jmp kermit

stat0:	mvi a,cmcfm
	call comnd		; Get a confirm.
	 jmp kermt3		;  Didn't get a confirm.
stat01:	lxi d,locst		; Get the address of the local echo string.
	mvi c,prstr		; Print it.
	call bdos
	lda ecoflg		; Get the local echo flag.
	cpi 0			; Is it on?
	jz stat02		; If not say so.
	lxi d,onstr		; Say on.
	jmp stat03
stat02:	lxi d,offstr		; Say off.
stat03:	mvi c,prstr		; Print it.
	call bdos

IF NOT (robin OR rainbo OR gener OR dmII)
	lxi d,vtemst		; Get the address of the VT52 emulation string.
	mvi c,prstr		; Print it.
	call bdos
	lda vtflg		; Get the VT52 emulation flag.
	cpi 0			; Is it on?
	jz stat1		; If not say so.
	lxi d,onstr		; Say on.
	jmp stat11
stat1:	lxi d,offstr		; Say off.
stat11:	mvi c,prstr		; Print it.
	call bdos
ENDIF				;NOT (robin OR rainbo OR gener OR dmII)

	lxi d,cpmst		; Get the address of the CPM created file.
	mvi c,prstr		; Print it.
	call bdos
	lda cpmflg		; Get the CPM flag.
	cpi 0			; Is it on?
	jz stat2		; If not say so.
	lxi d,onstr		; Say on.
	jmp stat21
stat2:	lxi d,offstr		; Say off.
stat21:	mvi c,prstr		; Print it.
	call bdos

	lxi d,ibmst		; IBM string.
	mvi c,prstr		; Print it.
	call bdos
	lda ibmflg		; IBM flag.
	cpi 0			; Is it on?
	jz stat3		; If not say so.
	lxi d,onstr		; Say on.
	jmp stat31
stat3:	lxi d,offstr		; Say off.
stat31:	mvi c,prstr		; Print it.
	call bdos

	lxi d,filst		; File warning string.
	mvi c,prstr		; Print it.
	call bdos
	lda flwflg		; File warning flag.
	cpi 0			; Is it on?
	jz stat4		; If not say so.
	lxi d,onstr		; Say on.
	jmp stat41
stat4:	lxi d,offstr		; Say off.
stat41:	mvi c,prstr		; Print it.
	call bdos

	lxi d,parst		; Parity string.
	mvi c,prstr		; Print it.
	call bdos
	lda parity		; Get the parity setting.
	lxi d,pnonst		; None by default.
	cpi parmrk		; Is it mark?
	jnz stat5		; If not say so.
	lxi d,pmrkst		; Say mark.
	jmp stat55
stat5:	cpi parspc		; Is it space?
	jnz stat51		; If not say so.
	lxi d,pspcst		; Say space.
	jmp stat55
stat51:	cpi parodd		; Is it odd?
	jnz stat52		; If not say so.
	lxi d,poddst		; Say odd.
	jmp stat55
stat52:	cpi parevn		; Is it even?
	jnz stat55		; If not say so.
	lxi d,pevnst		; Say even.
stat55:	mvi c,prstr		; Print it.
	call bdos

	lxi d,escst		; Escape string.
	mvi c,prstr		; Print it.
	call bdos
	call escpr		; Print the escape char.

	lxi d,crlf		; Get the address of a crlf.
	mvi c,prstr		; Print it.
	call bdos
IF osbrn1
	lxi	h,300H	; Assume 300 baud
	lda	osbaud
	ora	a
	jz	stat61
	mvi	h,12H	; No, it's 1200
stat61:	call	nout	; Print either "300" or "1200"
	lxi	d,osbmsg	; Print " baud",cr,lf
	mvi	c,prstr
	call	bdos
ENDIF ; osbrn1
	ret

; Print the escape char.

escpr:	lda escchr		; Get the escape char.
	cpi ' '			; Is it a control char?
	jp escpr2
	mvi c,prstr		; Output Control-.
	lxi d,inms10
	call bdos
	lda escchr
	ori 100O		; De-controlify.
escpr2:	mvi c,conout		; Output the char
	mov e,a
	call bdos
	ret

;************************System Dependent****************************

IF osi OR apple
prtout:	lxi h,mnport		; Output it.
	mov m,e
	ret
ENDIF				;osi OR apple


IF osbrn1
prtout:	mov	a,e
	jmp	OSSTDA
ENDIF ; osbrn1

IF brain OR heath OR z100 OR trs80 OR telcon
prtout:	in mnprts		; Get the output ready flag.
	ani output		; Is it set?
	jz prtout		; If so, loop until it isn't.
	mov a,e			; Get the char to output.
prtou2:	out mnport		; Output it.
	ret
ENDIF ; brain OR heath OR z100 OR trs80 OR telcon

IF vector
prtout:	mov a,e			; Get the char to output.
	out mnport		; Output it.
	ret
ENDIF				;vector

;*This is Nick Bush's VT180 port switching support.  It's incompatible
;*with Bernie's code -- Bernie, can you reconcile these?
;
;IF robin
;prtout:lda gppflg		; Check if using general port
;	cpi 0			;  .  .  .
;	jz prtouc		; No, using comm port
;
;prtoug:in gentst		; Get general port flags
;	ani output		; Ready for output?
;	jz prtoug		; If not, wait until it is
;	mov a,e			; Get the character to print
;	out gendat		; and send it
;	ret			; All done
;
;prtouc:in comtst		; Get the output ready flag.
;	ani output		; Is it set?
;	jz prtout		; If so, loop until it isn't.
;	mov a,e			; Get the char to output.
;	out comdat		; Output it.
;	ret
;ENDIF

IF gener OR rainbo OR robin OR dmII
prtout:	mvi c,punout		;Get Char in E to COMM-port
	call bdos
	ret
ENDIF				;gener OR rainbo OR robin OR dmII


;	Utility routines

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

rskp:	pop h			; Get the return address.
	inx h			; Increment by three.
	inx h
	inx h
	pchl

; Jumping here is the same as a ret.

r:	ret

; This routine prints the number in HL on the screen, in hex.
; (Thanks to Jeff Damens)  (Not currently used, now we print in decimal)
; (but let's keep it around in case we need again for something)
;
;nout:	mvi a,0
;	sta temp4
;	mov a,h
;	push psw		; Save argument.
;	ani 0F0H		; Only want high order nibble.
;	rrc
;	rrc
;	rrc
;	rrc
;	call pdig		; Print the digit.
;	pop psw			; Restore argument.
;	ani 0FH			; Just the low order nibble.
;	call pdig
;	mov a,l
;	push psw		; Save argument.
;	ani 0F0H		; Only want high order nibble.
;	rrc
;	rrc
;	rrc
;	rrc
;	call pdig		; Print the digit.
;	mvi a,0FFH
;	sta temp4		; Make sure at least one zero is printed.
;	pop psw			; Restore argument.
;	ani 0FH			; Just the low order nibble.
;
;	; print the digit in register a
;
;pdig:	push psw		; Save the digit.
;	cpi 0
;	jnz pdig2
;	lda temp4		; Is the print zero flag set?
;	cpi 0
;	jnz pdig2
;	pop psw
;	ret
;pdig2:	mvi a,0FFH		; Set the print zero flag.
;	sta temp4
;	pop psw			; Restore the digit.
;	cpi 10			; Do we use digits or a-f?
;	jm usedig		; Digit.
;	adi 'A'-10		; Compute digit
;	jmp havdig		; and proceed.
;usedig:adi '0' 		; Convert to digit
;havdig:mov e,a
;	mvi c,conout
;	push h
;	call bdos
;	pop h			; Save h & l from bdos
;	ret			; and return.

; This routine prints the number in HL on the screen in decimal.
; Saves all ACs.

nout:	push psw		; Save our ACs.
	push b
	push d
	push h
	lxi b,-10		; Get some useful constants.
	lxi d,-1

nout2:	dad b			; Subtract as many 10s as possible.
	inx d			; Count them.
	jc nout2		; If some left keep going.

	lxi b,10		; Restore the last 10 we took away.
	dad b
	xchg			; Swap the remainder and the quotient.
	mov a,h			; Get the number of 10s found.
	ora l			;* I think this checks if h equals zero.  If
				;* so, this should just be a CPI 0 for clarity.
	cnz nout		; If non zero, recurse.
	mov a,e			; Get the remainder.
	adi '0'			; Make the number printable.
	mov e,a			; Output the digit.
	mvi c,conout
	call bdos

	pop h			; Restore the ACs.
	pop d
	pop b
	pop psw
	ret

;	This set of routines provides a user oriented way of parsing
;	commands.  It is similar to that of the COMND JSYS in TOPS-20.


;	This routine prints the prompt in DE and specifies the reparse
;	address.

prompt:	pop h			; Get the return address.
	push h			; Put it on the stack again.
	shld cmrprs		; Save it as the address to go to on reparse.
	lxi h,0			; Clear out hl pair.
	dad sp			; Get the present stack pointer.
	shld cmostp		; Save for later restoral.
	xchg			; Save the pointer to the prompt.
	shld cmprmp
	xchg
	lxi h,cmdbuf
	shld cmcptr		; Initialize the command pointer.
	shld cmdptr
	mvi a,0
	sta cmaflg		; Zero the flags.
	sta cmccnt
	mvi a,0FFH		; Try it this way (Daphne.)
	sta cmsflg
	mvi c,prstr
	lxi d,cmcrlf
	call bdos
	mvi c,prstr		; Print the prompt.
	lhld cmprmp
	xchg
	call bdos
	ret

;	This address is jumped to on reparse.

repars:	lhld cmostp		; Get the old stack pointer.
	sphl			; Make it the present one.
	lxi h,cmdbuf
	shld cmdptr
	mvi a,0FFH		; Try it this way (Daphne.)
	sta cmsflg
	lhld cmrprs		; Get the reparse address.
	pchl			; Go there.

;	This address can be jumped to on a parsing error.

prserr:	lhld cmostp		; Get the old stack pointer.
	sphl			; Make it the present one.
	lxi h,cmdbuf
	shld cmcptr		; Initialize the command pointer.
	shld cmdptr
	mvi a,0
	sta cmaflg		; Zero the flags.
	sta cmccnt
	mvi a,0FFH		; Try it this way (Daphne.)
	sta cmsflg
	mvi c,prstr
	lxi d,cmcrlf
	call bdos
	mvi c,prstr		; Print the prompt.
	lhld cmprmp		; Get the prompt.
	xchg
	call bdos
;* Instead return to before the prompt call.
	lhld cmrprs
	pchl

;	This routine parses the specified function in A.  Any additional
;	information is in DE and HL.
;	Returns +1 on success
;		+4 on failure (assumes a JMP follows the call)

comnd:	sta cmstat		; Save what we are presently parsing.
	call cminbf		; Get chars until an action or a erase char.
	cpi cmcfm		; Parse a confirm?
	jz cmcfrm		; Go get one.
	cpi cmkey		; Parse a keyword?
	jz cmkeyw		; Try and get one.
	cpi cmifi		; Parse an input file spec?
	jz cmifil		; Go get one.
	cpi cmofi		; Output file spec?
	jz cmofil		; Go get one.
	cpi cmtxt		; Parse arbitrary text?
	jz cmtext		; Go do it.
	mvi c,prstr		; Else give an error.
	lxi d,cmer00		; "?Unrecognized COMND call"
	call bdos
	ret

;	This routine parses arbitrary text up to a CR.
;	Accepts DE:	address to put text
;	Returns in A:	number of chars in text (may be 0)
;		  DE:	updated pointer

cmtext:	xchg			; Put the pointer to the dest in HL.
	shld cmptab		; Save the pointer.
	mvi b,0			; Init the char count
cmtxt1:	call cmgtch		; Get a char.
	cpi 0			; Terminator?
	jp cmtxt5		; No, put in user space.
	ani 7FH			; Turn off minus bit.
	cpi esc			; An escape?
	jnz cmtxt2		; No.
	mvi c,conout
	mvi e,bell		; Get a bell.
	call bdos
	mvi a,0
	sta cmaflg		; Turn off the action flag.
	lhld cmcptr		; Move the pointer to before the escape.
	dcx h
	shld cmcptr
	shld cmdptr
	lxi h,cmccnt		; Get the char count.
	dcr m			; Decrement it by one.
	jmp cmtxt1		; Try again.
	
cmtxt2:	cpi '?'			; Is it a question mark?
	jz cmtxt3		; If so put it in the text.
	cpi ff			; Is it a formfeed?
	cz cmblnk		; If so blank the screen.
	mov a,b			; Return the count.
	lhld cmptab		; Return updated pointer in HL.
	xchg
	jmp rskp		; Return success.

cmtxt3:	lxi h,cmaflg		; Point to the action flag.
	mvi m,0			; Set it to zero.
cmtxt5:	inr b			; Increment the count.
	lhld cmptab		; Get the pointer.
	mov m,a			; Put the char in the array.
	inx h
	shld cmptab		; Save the updated pointer.
	jmp cmtxt1		; Get another char.


; This routine gets a confirm.

cmcfrm:	call cmgtch		; Get a char.
	cpi 0			; Is it negative (a terminator; a space or
				;  a tab will not be returned here as they
				;  will be seen as leading white space.)
	rp			; If not, return failure.
	ani 7FH			; Turn off the minus bit.
	cpi esc			; Is it an escape?
	jnz cmcfr2
	mvi c,conout
	mvi e,bell		; Get a bell.
	call bdos
	mvi a,0
	sta cmaflg		; Turn off the action flag.
	lhld cmcptr		; Move the pointer to before the escape.
	dcx h
	shld cmcptr
	shld cmdptr
	lxi h,cmccnt		; Get the char count.
	dcr m			; Decrement it by one.
	jmp cmcfrm		; Try again.
cmcfr2:	cpi '?'			; Curious?
	jnz cmcfr3
	mvi c,prstr		; Print something useful.
	lxi d,cmin00
	call bdos
	mvi c,prstr
	lxi d,cmcrlf		; Print a crlf.
	call bdos
	mvi c,prstr
	lhld cmprmp		; Reprint the prompt.
	xchg
	call bdos
	lhld cmdptr		; Get the pointer into the buffer.
	mvi a,'$'		; Put a $ there for printing.
	mov m,a
	lhld cmcptr
	dcx h			; Decrement and save the buffer pointer.
	shld cmcptr
	mvi c,prstr
	lxi d,cmdbuf
	call bdos
	mvi a,0			; Turn off the action flag.
	sta cmaflg
	jmp repars		; Reparse everything.

cmcfr3:	cpi ff			; Is it a form feed?
	cz cmblnk		; If so blank the screen.
	jmp rskp

;	This routine parses a keyword from the table pointed
;	to in DE.  The format of the table is as follows:
;
;	addr:	db	n	; Where n is the # of entries in the table.
;		db	m	; M is the size of the keyword.
;		db	'string$' ; Where string is the keyword.
;		db	a,b	; Where a & b are pieces of data
;				;  to be returned.  (Must be two of them.)
;
;	The keywords must be in alphabetical order.

cmkeyw:	shld cmhlp		; Save the help.
	xchg			; Get the address of the table.
	shld cmptab		; Save the beginning of keyword tab for '?'.
	mov b,m			; Get the number of entries in the table.
	inx h
	shld cmkptr
	lhld cmdptr		; Save the command pointer.
	shld cmsptr
cmkey2: mov a,b			; Get the number of entries left.
	cpi 0			; Any left?
	rz			; If not we failed.
	lhld cmkptr
	mov e,m			; Get the length of the keyword.
	inx h
cmkey3:	dcr e			; Decrement the number of chars left.
	mov a,e
	cpi 0FFH		; Have we passed the end?
	jm cmkey5		; If so go to the next.
	call cmgtch		; Get a char.
	cpi 0			; Is it a terminater?
	jp cmkey4		; If positive, it is not.
	ani 7FH			; Turn off the minus bit.
	cpi '?'
	jnz cmky31
	mvi a,0
	sta cmaflg		; Turn off the action flag.
	lxi h,cmccnt		; Decrement the char count.
	dcr m
;* Must go through the keyword table and print them.
	mvi c,prstr		
	lhld cmhlp		; For now print the help text.
	xchg
	call bdos
	mvi c,prstr
	lxi d,cmcrlf		; Print a crlf.
	call bdos
	mvi c,prstr
	lhld cmprmp		; Reprint the prompt.
	xchg
	call bdos
	lhld cmdptr		; Get the pointer into the buffer.
	mvi a,'$'		; Put a $ there for printing.
	mov m,a
	lhld cmcptr
	dcx h			; Decrement and save the buffer pointer.
	shld cmcptr
	mvi c,prstr
	lxi d,cmdbuf
	call bdos
	jmp repars		; Reparse everything.

cmky31:	cpi esc			; Is it an escape?
	jnz cmky35
	mvi a,0
	sta cmaflg		; Turn off the action flag.
	push d
	push b
	push h
	call cmambg
	 jmp cmky32		; Not ambiguous.
	mvi c,conout
	mvi e,bell
	call bdos		; Ring the bell.
	lhld cmcptr		; Move the pointer to before the escape.
	dcx h
	shld cmcptr
	shld cmdptr
	lxi h,cmccnt		; Get the char count.
	dcr m			; Decrement it by one.
	pop h
	pop b
	pop d
	inr e			; Increment the left to parse char count.
	jmp cmkey3
cmky32:	lhld cmcptr		; Pointer into buffer.
	dcx h			; Backup to the escape.
	xchg
	pop h
	push h
cmky33:	mov a,m			; Get the next char.
	cpi '$'			; Finished?
	jz cmky34
	inx h
	xchg
	mov m,a			; Move it into the buffer.
	inx h
	xchg
	lda cmccnt		; Increment the char count.
	inr a
	sta cmccnt
	jmp cmky33
cmky34:	lda cmccnt		; Get the character count.
	inr a			; Increment and save it.
	sta cmccnt
	xchg			; Put the command buffer pointer in HL.
	mvi a,' '		; Get a blank.
	mov m,a			; Put it in the command buffer.
	inx h			; Increment the pointer
	shld cmcptr		; Save the updated pointer.
	shld cmdptr
	pop h
	push h
	xchg
	mvi c,prstr		; Print the rest of the keyword.
	call bdos
	mvi c,conout
	mvi e,' '
	call bdos		; Print a blank.
	pop h
	pop b
	pop d
	jmp cmky37
cmky35:	push h
	push d
	call cmambg
	 jmp cmky36
	mvi c,prstr
	lxi d,cmer01
	call bdos		; Say its ambiguous.
	jmp prserr		; Give up.
cmky36:	pop d
	pop h
cmky37:	inr e			; Add one incase it is negative.
	mvi d,0
	dad d			; Increment past the keyword.
	inx h			; Past the $. 
	mov d,m			; Get the data.
	inx h
	mov e,m
	mov a,e
	jmp rskp
cmkey4:	cpi 'a'			; Is it less than a?
	jm cmky41		; If so don't capitalize it.
	cpi 'z'+1		; Is it more than z?
	jp cmky41		; If so don't capitalize it.
	ani 137O		; Capitalize it.
cmky41:	mov d,m			; Get the next char of the keyword.
	inx h
	cmp d			; Match?
	jz cmkey3		; If so get the next letter.

cmkey5:	mvi d,0
	mov a,e			; Get the number of chars left.
	cpi 0			; Is it negative?
	jp cmky51
	mvi d,0FFH		; If so, sign extend.
cmky51:	dad d			; Increment past the keyword.
	lxi d,0003H		; Plus the $ and data.
	dad d
	shld cmkptr
	dcr b			; Decrement the number of entries left.
	lhld cmsptr		; Get the old cmdptr.
	shld cmdptr		; Restore it.
;* check so we don't pass it.
	jmp cmkey2		; Go check the next keyword.

cmambg:	dcr b			; Decrement the number of entries left.
	rm			; If none left then it is not ambiguous.
	inr e			; This is off by one; adjust.
	mov c,e			; Save the char count.
	mov a,e
	cpi 0			; Any chars left?
	rz			; No, it can't be ambiguous.
	mvi d,0
	dad d			; Increment past the keyword.
	mvi e,3			; Plus the $ and data.
	dad d
	mov b,m			; Get the length of the keyword.
	inx h
	xchg
	lhld cmkptr		; Get pointer to keyword entry.
	mov a,m			; Get the length of the keyword.
	sub c			; Subtract how many left.
	mov c,a			; Save the count.
	cmp b
	jz cmamb0
	rp			; If larger than the new word then not amb.
cmamb0:	lhld cmsptr		; Get the pointer to what parsed.
cmamb1:	dcr c			; Decrement the count.
	jm rskp			; If we are done then it is ambiguous.
	xchg			; Exchange the pointers.
	mov b,m			; Get the next char of the keyword
	inx h
	xchg			; Exchange the pointers.
	mov a,m			; Get the next parsed char.
	inx h
	cpi 'a'			; Is it less than a?
	jm cmamb2		; If so don't capitalize it.
	cpi 'z'+1		; Is it more than z?
	jp cmamb2		; If so don't capitalize it.
	ani 137O
cmamb2:	cmp b			; Are they equal?
	rnz			; If not then its not ambiguous.
	jmp cmamb1		; Check the next char.

cmifil:	xchg			; Get the fcb address.
	shld cmfcb		; Save it.
	mvi e,0			; Initialize char count.
	mvi m,0			; Set the drive to default to current.
	inx h
	shld cmfcb2
	mvi a,0			; Initialize counter.
	mvi b,' '
cmifi0:	mov m,b			; Blank the FCB.
	inx h
	inr a
	cpi 0CH			; Twelve?
	jm cmifi0
cmifi1:	call cmgtch		; Get another char.
	cpi 0			; Is it an action character.
	jp cmifi2
	ani 7FH			; Turn off the action bit.
	cpi '?'			; A question mark?
	jnz cmif12
	lxi h,cmaflg		; Blank the action flag.
	mvi m,0
	lhld cmcptr		; Decrement the buffer pointer.
	dcx h
	shld cmcptr
	jmp cmifi8		; Treat like any other character.
cmif12:	cpi esc			; An escape?
	jnz cmif13
	mvi a,0
	sta cmaflg		; Turn off the action flag.
	mvi c,conout
	mvi e,bell
	call bdos		; Ring the bell.
	lhld cmcptr		; Move the pointer to before the escape.
	dcx h
	shld cmcptr
	shld cmdptr
	lxi h,cmccnt		; Get the char count.
	dcr m			; Decrement it by one.
	jmp repars
cmif13:	mov a,e			; It must be a terminator.
	cpi 0			; Test the length of the file name.
	jz cmifi9		; If zero complain.
	cpi 0DH
	jp cmifi9		; If too long complain.
	jmp rskp		; Otherwise we have succeeded.
cmifi2:	cpi '.'
	jnz cmifi3
	inr e
	mov a,e
	cpi 1H			; Any chars yet?
	jz cmifi9		; No, give error.
	cpi 0AH			; Tenth char? 
	jp cmifi9		; Past it, give an error.
	mvi c,9H
	mvi b,0
	lhld cmfcb
	dad b			; Point to file type field.
	shld cmfcb2
	mvi e,9H		; Say we've gotten nine.
	jmp cmifi1		; Get the next char.
cmifi3:	cpi ':'
	jnz cmifi4
	inr e
	mov a,e
	cpi 2H			; Is it in the right place for a drive?
	jnz cmifi9		; If not, complain.
	lhld cmfcb2
	dcx h			; Point to previous character.
	mov a,m			; Get the drive name.
	sui '@'			; Get the drive number.
	shld cmfcb2		; Save pointer to beginning of name field.
	dcx h			; Point to drive number.
	mov m,a			; Put it in the fcb.
	mvi e,0			; Start character count over.
	jmp cmifi1
cmifi4:	cpi '*'
	jnz cmifi7
	mov a,e
	cpi 8H			; Is this in the name or type field?
	jz cmifi9		; If its where the dot should be give up.
	jp cmifi5		; Type.
	mvi b,8H		; Eight chars.
	jmp cmifi6
cmifi5:	mvi b,0CH		; Three chars.
cmifi6:	lhld cmfcb2		; Get a pointer into the FCB.
	mvi a,'?'
	mov m,a			; Put a question mark in.
	inx h
	shld cmfcb2
	inr e
	mov a,e
	cmp b
	jm cmifi6		; Go fill in another.
	jmp cmifi1		; Get the next char.
cmifi7:	cpi '0'
	jm cmifi9
	cpi 'z'+1
	jp cmifi9
	cpi 'A'			; Don't capitalize non-alphabetics.
	jm cmifi8
	ani 137O		; Capitalize.
cmifi8:	lhld cmfcb2		; Get the pointer into the FCB.
	mov m,a			; Put the char there.
	inx h
	shld cmfcb2
	inr e
	jmp cmifi1

cmifi9:	mvi c,prstr
	lxi d,cmer02
	call bdos
	ret

cmofil:	jmp cmifil		; For now, the same as CMIFI.

cminbf:	push psw
	push d
	push h
	lda cmaflg		; Is the action char flag set?
	cpi 0
	jnz cminb9		; If so get no more chars.
cminb1:	lxi h,cmccnt		; Increment the char count.
	inr m
	mvi c,conin		; Get a char.
	call bdos
	lhld cmcptr		; Get the pointer into the buffer.
	mov m,a			; Put it in the buffer.
	inx h
	shld cmcptr
	cpi 25O			; Is it a ^U?
	jnz cminb2
cmnb12:	mvi c,prstr
	lxi d,clrlin		; Clear the line.
	call bdos
	mvi c,prstr
	lhld cmprmp		; Print the prompt.
	xchg
	call bdos
	lxi h,cmdbuf
	shld cmcptr		; Reset the point to the start.
	lxi h,cmccnt		; Zero the count.
	mvi m,0
	jmp repars		; Go start over.
cminb2:	cpi 10O			; Or backspace?
	jz cminb3
	cpi del			; Delete?
	jnz cminb4
	mvi c,prstr		; Print the delete string.
	lxi d,delstr
	call bdos
cminb3:	lda cmccnt		; Decrement the char count by two.
	dcr a
	dcr a
	cpi 0			; Have we gone too far?
	jp cmnb32		; If not proceed.
	mvi c,conout		; Ring the bell.
	mvi e,bell
	call bdos
	jmp cmnb12		; Go reprint prompt and reparse. 
cmnb32:	sta cmccnt		; Save the new char count.
	mvi c,prstr		; Erase the character.
	lxi d,clrspc
	call bdos
	lhld cmcptr		; Get the pointer into the buffer.
	dcx h			; Back up in the buffer.
	dcx h
	shld cmcptr
	jmp repars		; Go reparse everything.
cminb4:	cpi '?'			; Is it a question mark.
	jz cminb6
	cpi esc			; Is it an escape?
	jz cminb6
	cpi cr			; Is it a carriage return?
	jz cminb5
	cpi lf			; Is it a line feed?
	jz cminb5
	cpi ff			; Is it a formfeed?
	jnz cminb7
	call cmblnk
cminb5:	lda cmccnt		; Have we parsed any chars yet?
	cpi 1
	jz prserr		; If not, just start over.
cminb6:	mvi a,0FFH		; Set the action flag.
	sta cmaflg
	jmp cminb9
cminb7:	cpi ' '
	jz cminb1		; Get another char.
	cpi tab
	jz cminb1		; Get another char.
	jmp cminb1		; Get another.

cminb9:	pop h
	pop d
	pop psw
	ret

cmgtch:	push h
	push b
cmgtc1:	lda cmaflg
	cpi 0			; Is it set.
	cz cminbf		; If the action char flag is not set get more.
	lhld cmdptr		; Get a pointer into the buffer.
	mov a,m			; Get the next char.
	inx h
	shld cmdptr
	cpi ' '			; Is it a space?
	jz cmgtc2
	cpi tab			; Or a tab?
	jnz cmgtc3
cmgtc2:	lda cmsflg		; Get the space flag.
	cpi 0			; Was the last char a space?
	jnz cmgtc1		; Yes, get another char.
	mvi a,0FFH		; Set the space flag.
	sta cmsflg
	mvi a,' '
	pop b
	pop h
	jmp cmgtc5
cmgtc3:	push psw
	mvi a,0
	sta cmsflg		; Zero the space flag.
	pop psw
	pop b
	pop h
	cpi esc
	jz cmgtc5
	cpi '?'			; Is the user curious?
	jz cmgtc4
	cpi cr
	jz cmgtc4
	cpi lf
	jz cmgtc4
	cpi ff
	rnz			; Not an action char, just return.
cmgtc4:	push h
	lhld cmdptr
	dcx h
	shld cmdptr
	pop h
cmgtc5:	ori 80H			; Make the char negative to indicate it is
	ret			;  a terminator. 

; This routine blanks the screen.

cmblnk:	mvi c,prstr		; Print the string to blank the screen.
	lxi d,clrtop
	call bdos
	ret

	; Pure storage.

outln2:	db	cr,lf,'Number of packets:'
	db	cr,lf,'Number of retries:'
	db	cr,lf,'File name:$'
kerm:	db	'Kermit-80>$'
delpr:	db	'Delete it? $'
crlf:	db	cr,lf,'$'
ermes1:	db	cr,lf,'?Unrecognized command$'
ermes2:	db	cr,lf,'?Illegal character$'
ermes3:	db	cr,lf,'?Not confirmed$'
ermes4:	db	'?Unable to receive initiate',cr,lf,'$'
ermes5:	db	'?Unable to receive file name',cr,lf,'$'
ermes6:	db	'?Unable to receive end of file',cr,lf,'$'
erms10:	db	'?Unable to receive data',cr,lf,'$'
erms11:	db	'?Disk full',cr,lf,'$'
erms14:	db	'?Unable to receive an acknowledgement from the host',cr,lf,'$'
erms15:	db	'?Unable to find file',cr,lf,'$'
erms16:	db	'?Unable to rename file$'
erms17: db	cr,lf,'?Disk full$'
erms18: db	cr,lf,'?Unable to tell host that the session is finished$'
erms19: db	cr,lf,'?Unable to tell host to logout$'
infms3:	db	bell,'Completed$'
infms4:	db	bell,'Failed$'
infms5:	db	'%Renaming file to $'
infms6:	db	cr,lf,'[Closing the log file]$'
infms7:	db	cr,lf,'[Connected to remote host, type $'
infms8:	db	'C to return]',cr,lf
IF NOT trs80
	db	'$'
ENDIF

IF trs80
	db	'(Control-_ is the Down-Arrow key on the TRS-80 keyboard)',cr,lf,'$'
ENDIF
infms9:	db	cr,lf,'[Connection closed, back at micro]$'
inms10:	db	'Control-$'
cfrmes:	db	' Confirm with carriage return $'
filhlp:	db	' Input file spec (possibly wild) $'
escmes:	db	cr,lf,'Type the new escape character:  $'
tophlp:	db	cr,lf,'BYE to host (LOGOUT) and exit to CP/M'
	db	cr,lf,'CONNECT to host on selected port'
	db	cr,lf,'EXIT to CP/M'
	db	cr,lf,'FINISH running Kermit on the host'
	db	cr,lf,'HELP by giving this message'
	db	cr,lf,'LOG the terminal session to a file'
	db	cr,lf,'LOGOUT the host'
	db	cr,lf,'RECEIVE file from host'
	db	cr,lf,'SEND file to host'
	db	cr,lf,'SET a parameter'
	db	cr,lf,'SHOW the parameters'
	db	cr,lf,'STATUS of Kermit$'
sethlp:

IF brain OR osbrn1
	db	cr,lf,'BAUD rate change'
ENDIF ; brain OR osbrn1
	db	cr,lf,'CPM-CREATED-FILE will be sent'
	db	cr,lf,'ESCAPE character change'
	db	cr,lf,'FILE-WARNING'
	db	cr,lf,'IBM (parity and turn around handling)'
	db	cr,lf,'LOCAL-ECHO echoing (half-duplex)'
;IF robin
;	db	cr,lf,'PORT (to communicate on)'
;ENDIF ; robin
	db	cr,lf,'PARITY to be used'

IF NOT (robin OR gener OR rainbo OR dmII)
	db	cr,lf,'VT52-EMULATION'
ENDIF				;NOT (robin OR gener OR robin OR dmII)
	db	'$'

stshlp:	db	cr,lf,'PAD-CHAR'
	db	cr,lf,'PADDING$'
;IF robin
;gpphlp:db	cr,lf,'COMMUNICATIONS - Communications port'
;	db	cr,lf,'GENERAL - General purpose port$'
;ENDIF ; robin
parhlp:	db	cr,lf,'EVEN	MARK	NONE	ODD	SPACE$'
onhlp:	db	cr,lf,'OFF	ON$'
yeshlp:	db	cr,lf,'NO	YES$'
inthlp:	db	cr,lf,'?  This message'
	db	cr,lf,'C  Close the connection'
IF apple
	db	cr,lf,'D  Close and disconnect the connection'
ENDIF				;apple
	db	cr,lf,'S  Status of the connection'
	db	cr,lf,'Typing the escape character will send it to the host'
	db	cr,lf,cr,lf,'Command>$'
onstr:	db	' on$'
offstr:	db	' off$'
locst:	db	cr,lf,'Local echo$'

IF NOT (robin OR gener OR rainbo OR dmII)
vtemst:	db	cr,lf,'VT52 emulation$'
ENDIF				;NOT (robin OR gener OR rainbo OR dmII)

cpmst:	db	cr,lf,'CPM created file$'
ibmst:	db	cr,lf,'IBM flag$'
filst:	db	cr,lf,'File warning$'
escst:	db	cr,lf,'Escape char: $'
parst:	db	cr,lf,'Parity: $'
pnonst:	db	'none$'
pmrkst:	db	'mark$'
pspcst:	db	'space$'
poddst:	db	'odd$'
pevnst:	db	'even$'
IF osbrn1
osbmsg:	db	' baud',cr,lf,'$'
ENDIF ; osbrn1

IF brain
baudtb:	db	('A'-100O),esc,'~kType the letter corresponding with the baud ra
te desired.'
	db	cr,lf,'(A)    50' 
	db	cr,lf,'(B)    75'
	db	cr,lf,'(C)   110'
	db	cr,lf,'(D)   134.5'
	db	cr,lf,'(E)   150'
	db	cr,lf,'(F)   300'
	db	cr,lf,'(G)   600'
	db	cr,lf,'(H)  1200'
	db	cr,lf,'(I)  1800'
	db	cr,lf,'(J)  2000'
	db	cr,lf,'(K)  2400'
	db	cr,lf,'(L)  3600'
	db	cr,lf,'(M)  4800'
	db	cr,lf,'(N)  7200'
	db	cr,lf,'(O)  9600'
	db	cr,lf,cr,lf,'Letter:  $'
ENDIF				;brain

IF osbrn1
baudtb:	db	cr,lf,'Type a letter corresponding to the baud rate desired.'
	db	cr,lf,'(A)   300'
	db	cr,lf,'(B)  1200'
	db	cr,lf,cr,lf,'Letter:  $'
ENDIF ; osbrn1

;***************************System Dependent**************************
IF brain
outlin:	db	('A'-100O),esc,'~k',cr,lf,tab,tab
versio:	db	'CUCCA SuperBrain Kermit-80 - V3.2',cr,lf,'$'
delstr:	db	10O,' ',10O,10O,'$' 	; Delete string.
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'~K$'		; Clear line.
clrtop:	db	('A'-100O),esc,'~k$' 	; Clear screen and go home.
scrnp:	db	esc,'Y#4$'		; Place for number of packets.
scrnrt:	db	esc,'Y#4',lf,'$'	; Place for number of retries.
scrfln:	db	esc,'Y%,',esc,'~K$'	; Place for file name.
screrr:	db	esc,'Y& $'		; Place for error messages.
scrst:	db	esc,'Y#T$'		; Place for "Complete".
scrend:	db	esc,'Y',27H,' $'	; Place for prompt.
ttab:					; Table start location.
ta:	db	('K'-100O),'$',0,0	; Cursor up.
tb:	db	12O,'$',0,0		; Cursor down.
tc:	db	('F'-100O),'$',0,0	; Cursor right.
td:	db	esc,'D$',0		; No translation.
te:	db	esc,'E$',0
tf:	db	esc,'F$',0
tg:	db	esc,'G$',0
th:	db	('A'-100O),'$',0,0	; Cursor home.
ti:	db	('K'-100O),'$',0,0	; Reverse linefeed.
tj:	db	esc,'~k$'		; Clear to end of screen.
tk:	db	esc,'~K$'		; Clear to end of line.
ENDIF					;brain

IF debug
rppos:	db	esc,'Y* RPack:',esc,'~K$'
sppos:	db	esc,'Y( SPack:',esc,'~K$'
ENDIF					;debug

IF osbrn1
outlin:	db	1AH,lf,lf,tab		; (Clear screen, home cursor)
versio:	db	'CUCCA/NIH Osborne 1  Kermit-80 - V3.2',cr,lf,'$'
delstr:	db	10O,10O,'$' 		; Delete string.
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'T$'		; Clear line.
clrtop:	db	1AH,'$'		; Clear screen and go home.
scrnp:	db	esc,'=',20H+03H,20H+15H,'$'	; Place for number of packets. 
scrnrt:	db	esc,'=',20H+03H,20H+15H,lf,'$'	; Place for number of retries. 
scrfln:	db	esc,'=',20H+05H,20H+0CH,'$'	; Place for file name. 
scrst:	db	esc,'=',20H+07H,20H+0FH,'$' 	; Place for status. 
scrend:	db	cr,lf,'$'
screrr:	db	esc,'=',20H+06H,20H+00H,'$' 	; Place for error messages. 
ttab:					; Table start location.	
ta:	db	('K'-100O),'$',0,0	; Cursor up.
tb:	db	12O,'$',0,0		; Cursor down.
tc:	db	('L'-100O),'$',0,0	; Cursor right.
td:	db	esc,'D$',0		; No translation.
te:	db	esc,'E$',0
tf:	db	esc,'F$',0
tg:	db	esc,'G$',0
th:	db	('^'-100O),'$',0,0	; Cursor home.
ti:	db	('K'-100O),'$',0,0	; Reverse linefeed.
tj:	db	esc,'T$',0	; (can't) Clear to end of screen.
tk:	db	esc,'T$'		; Clear to end of line.
ENDIF ; osbrn1

IF apple
outlin:	db	('^'-100O),esc,'Y',cr,lf,tab
versio:	db	'CUCCA/DEC APPLE ][ Kermit-80 - V3.2',cr,lf,'$'
delstr:	db	10O,10O,'$' 		; Delete string.
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'T$'		; Clear line.
clrtop:	db	('^'-100O),esc,'Y$' 	; Clear screen and go home.
scrnp:	db	esc,'=',20H+03H,20H+15H,'$'	; Place for number of packets. 
scrnrt:	db	esc,'=',20H+04H,20H+15H,'$'	; Place for number of retries. 
scrfln:	db	esc,'=',20H+05H,20H+0CH,'$'	; Place for file name. 
screrr:	db	esc,'=',20H+06H,20H+00H,'$'	; Place for error messages. 
scrst:	db	esc,'=',20H+07H,20H+0FH,'$'	; Place for "Complete".
scrend:	db	cr,lf,'$'			; Place for prompt.
ttab:					; Table start location.	
ta:	db	('K'-100O),'$',0,0	; Cursor up.
tb:	db	12O,'$',0,0		; Cursor down.
tc:	db	('F'-100O),'$',0,0	; Cursor right.
td:	db	esc,'D$',0		; No translation.
te:	db	esc,'E$',0
tf:	db	esc,'F$',0
tg:	db	esc,'G$',0
th:	db	('^'-100O),'$',0,0	; Cursor home.
ti:	db	('K'-100O),'$',0,0	; Reverse linefeed.
tj:	db	esc,'Y$',0		; Clear to end of screen.
tk:	db	esc,'T$'		; Clear to end of line.
ENDIF					;apple

IF vector
outlin:	db	('D'-100O),cr,lf,tab,tab
versio:	db	'CUCCA Vector Graphics Kermit-80 - V3.2',cr,lf,'$'
delstr:	db	10O,' ',10O,10O,'$' 	; Delete string.
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,('Q'-100O),'$'	; Clear line. 
clrtop:	db	('D'-100O),'$'	 	; Clear screen and go home.
scrnp:	db	esc,15H,03H,'$'		; Place for number of packets.
scrnrt:	db	esc,15H,04H,'$'		; Place for number of retries.
scrfln:	db	esc,0CH,05H,('Q'-100O),'$' ; Place for file name.
screrr:	db	esc,00H,06H,'$'		; Place for error messages.
scrst:	db	esc,34H,03H,'$'		; Place for "Complete".
scrend:	db	esc,00H,07H,'$'		; Place for prompt.
ttab:					; Table start location.
ta:	db	('U'-100O),'$',0,0	; Cursor up.
tb:	db	12O,'$',0,0		; Cursor down.
tc:	db	('Z'-100O),'$',0,0	; Cursor right.
td:	db	esc,'D$',0		; No translation.
te:	db	esc,'E$',0
tf:	db	esc,'F$',0
tg:	db	esc,'G$',0
th:	db	('B'-100O),'$',0,0	; Cursor home.
ti:	db	('U'-100O),'$',0,0	; Reverse linefeed.
tj:	db	('P'-100O),'$',0,0	; Clear to end of screen.
tk:	db	('Q'-100O),'$'		; Clear to end of line.
ENDIF				; vector

IF telcon
outlin:	db	esc,'H',esc,'J',cr,lf,tab,tab
versio:	db	'CUCCA/Stevens Telcon Kermit-80 V3.2',cr,lf,'$'
ENDIF

IF heath
outlin:	db	esc,'E',esc,'H',cr,lf,tab,tab
versio:	db	'CUCCA/DEC Heath/Zenith 89 Kermit-80 - V3.2',cr,lf,'$'
ENDIF				; heath

IF z100
outlin:	db	esc,'E',esc,'H',cr,lf,tab,tab
versio:	db	'CUCCA/Stevens Zenith Z-100 Kermit-80 - V3.2',cr,lf,'$'
ENDIF				; z100

IF heath OR z100 OR telcon
delstr: db	10O,' ',10O,'$'	;delete string
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'l$'		; Clear line.
clrtop:	db	esc,'E',esc,'H$' 	; Clear screen and go home.
scrnp:	db	esc,'Y#3$'		; Place for number of packets.
scrnrt:	db	esc,'Y#3',lf,'$'	; Place for number of retries.
scrfln:	db	esc,'Y%+',esc,'K$' 	; Place for file name.
screrr:	db	esc,'Y  $'		; Place for error messages.
scrst:	db	esc,'Y& $'		; Place for "Complete".
scrend:	db	cr,lf,'$'		; Place for prompt.
ttab:					; Table start location.
ta:	db	esc,'A$',0		; Cursor up.
tb:	db	esc,'B$',0		; Cursor down.
tc:	db	esc,'C$',0		; Cursor right.
td:	db	esc,'D$',0		; Cursor left
te:	db	esc,'E$',0		; Clear display
tf:	db	esc,'F$',0		; Enter Graphics Mode
tg:	db	esc,'G$',0		; Exit Graphics mode
th:	db	esc,'H$',0		; Cursor home.
ti:	db	esc,'I$',0		; Reverse linefeed.
tj:	db	esc,'J$',0		; Clear to end of screen.
tk:	db	esc,'K$',0		; Clear to end of line.
ENDIF					;heath OR z100 OR telcon

IF trs80
outlin:	db	esc,':',cr,lf,tab,tab
versio:	db	'CUCCA/Cerritos TRS-80 II Kermit-80 V3.2',cr,lf,'$'
delstr: db	10O,' ',10O,'$'		;delete string
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'T$'		; Clear line.
clrtop:	db	esc,':$'		; Clear screen and go home.
scrnp:	db	esc,'=#5$'		; Place for number of packets.
scrnrt:	db	esc,'=#5',lf,'$'       	; Place for number of retries.
scrfln:	db	esc,'=%+',esc,'T$' 	; Place for file name.
scrst:	db	esc,'=#T$'		; Place for status.
scrend:	db	cr,lf,'$'
screrr:	db	esc,'=& $'		; Place for error messages.
ttab:					; Table start location.
ta:	db	0BH,'$',0		; Cursor up.
tb:	db	0AH,'$',0		; Cursor down.
tc:	db	0CH,'$',0		; Cursor right.
td:	db	08H,'$',0		; Cursor left
te:	db	esc,':$',0		; Clear display
tf:	db	esc,'F$',0		; Enter Graphics Mode
tg:	db	esc,'G$',0		; Exit Graphics mode
th:	db	1EH,'$',0		; Cursor home.
ti:	db	0BH,'$',0		; Reverse linefeed.
tj:	db	esc,'Y$',0		; Clear to end of screen.
tk:	db	esc,'T$',0		; Clear to end of line.
ENDIF ; trs80

IF robin
outlin:	db	esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab
versio:	db	esc,'[1mCUCCA/DEC VT18X Kermit-80 - V3.2'
	db	esc,'[0m',cr,lf,'$'
ENDIF				; robin

IF rainbo
outlin:	db	esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab
versio:	db	esc,'[1mCUCCA/DEC Rainbow-100 CP/M-80 Kermit-80 - V3.2'
	db	esc,'[0m',cr,lf,'$'
ENDIF					; rainbo

IF dmII
outlin:	db	esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab
versio:	db	esc,'[1mCUCCA/DEC DECmate II CP/M-80 Kermit-80 - V3.2'
	db	esc,'[0m',cr,lf,'$'
ENDIF					; dmII

IF robin OR rainbo OR dmII
delstr: db	10O,' ',10O,'$'	;delete string
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	cr,esc,'[K$'		; Clear line.
clrtop:	db	esc,'[H',esc,'[J$' 	; Clear screen and go home.
scrnp:	db	esc,'[4;22H$'		; Place for number of packets.
scrnrt:	db	esc,'[5;22H$'		; Place for number of retries.
scrfln:	db	esc,'[6;12H',esc,'[K$'	; Place for file name.
screrr:	db	esc,'[7;1H$'		; Place for error messages.
scrst:	db	esc,'[4;53H$'		; Place for "Complete".
scrend:	db	esc,'[8;1H$'		; Place for prompt.
ENDIF					;robin OR rainbo OR dmII

IF gener
outlin: db	cr,lf,'Starting ...$'
versio:	db	cr,lf,'CUCCA/DEC Generic CP/M-80 Kermit-80 - V3.2',cr,lf,'$'
ENDIF					; gener

IF osi
outlin:	db	cr,lf,'Starting ...$'
versio:	db	'CUCCA OSI Kermit-80 - V3.2',cr,lf,'$'
ENDIF					; osi

IF gener OR osi
delstr: db	10O,' ',10O,'$'		;delete string
clrspc:	db	' ',10O,'$'		; Clear space.
clrlin:	db	'^U',cr,lf,'$'		; Clear line.
clrtop:	db	cr,lf,'$'		; "Home & clear" (best we can do).
scrnp:	db	' ','$'     		; Place for number of packets.
scrnrt:	db	' ','%$'		; Place for number of retries.
scrfln:	db	cr,lf,'$'		; Place for file name.
scrst:	db	cr,lf,'$'		; Place for status.
screrr:	db	cr,lf,'$'		; Place for error messages.
scrend:	db	cr,lf,'$'		; Place for prompt.
ENDIF					; gener OR osi

	; COMND tables

comtab:	db	0CH		; Twelve entries.
	db	03H,'BYE$',21H,21H
	db	07H,'CONNECT$',00H,00H
	db	04H,'EXIT$',03H,03H
	db	06H,'FINISH$',1BH,1BH
	db	04H,'HELP$',06H,06H
	db	03H,'LOG$',09H,09H
	db	06H,'LOGOUT$',1EH,1EH
	db	07H,'RECEIVE$',0CH,0CH
	db	04H,'SEND$',0FH,0FH
	db	03H,'SET$',12H,12H
	db	04H,'SHOW$',15H,15H
	db	06H,'STATUS$',18H,18H

settab:

IF brain OR osbrn1
	db	0AH		; Ten entries.	
	db	04H,'BAUD$',1BH,1BH
ENDIF ; brain OR osbrn1

IF NOT (brain OR osbrn1)
	db	09H		; Nine entries.	
ENDIF ; NOT (brain OR osbrn1)


	db	10H,'CPM-CREATED-FILE$',12H,12H
	db	06H,'ESCAPE$',00H,00H
	db	0CH,'FILE-WARNING$',0FH,0FH
	db	03H,'IBM$',03H,03H
	db	0AH,'LOCAL-ECHO$',06H,06H
	db	06H,'PARITY$',15H,15H
;IF robin
;	db	04H,'PORT$',1BH,1BH
;ENDIF ; robin
	db	07H,'RECEIVE$',09H,09H
	db	04H,'SEND$',0CH,0CH

IF NOT (robin OR gener OR rainbo OR dmII)
	db	0EH,'VT52-EMULATION$',18H,18H
ENDIF				;NOT (robin OR gener OR rainbo OR dmII)

stsntb:	db	02H
	db	08H,'PAD-CHAR$',00H,00H
	db	07H,'PADDING$',03H,03H

partab:	db	05H		; Five entries.
	db	04H,'EVEN$',parevn,parevn
	db	04H,'MARK$',parmrk,parmrk
	db	04H,'NONE$',parnon,parnon
	db	03H,'ODD$',parodd,parodd
	db	05H,'SPACE$',parspc,parspc

ontab:	db	02H		; Two entries.
	db	02H,'ON$',01H,01H
	db	03H,'OFF$',00H,00H

;IF robin
;gpptab:db	02H		; Two entries
;	db	0EH,'COMMUNICATIONS$',00H,00H
;	db	07H,'GENERAL$',01H,01H
;ENDIF ; robin

yestab:	db	02H		; Two entries.
	db	02H,'NO$',00H,00H
	db	03H,'YES$',01H,01H

cmer00:	db	cr,lf,'?Program error:  Invalid COMND call$'
cmer01:	db	cr,lf,'?Ambiguous$'
cmer02:	db	cr,lf,'?Illegal input file spec$'
cmin00:	db	' Confirm with carriage return$'
cmcrlf:	db	cr,lf,'$'

	; Impure data

; COMND storage

cmstat:	ds	1		; What is presently being parsed.
cmaflg:	ds	1		; Non-zero when an action char has been found.
cmccnt:	ds	1		; Non-zero if a significant char is found.
cmsflg:	ds	1		; Non-zero when the last char was a space.
cmostp:	ds	2		; Old stack pointer for reparse.
cmrprs:	ds	2		; Address to go to on reparse.
cmprmp:	ds	2		; Address of prompt.
cmptab:	ds	2		; Address of present keyword table.
cmhlp:	ds	2		; Address of present help.
cmdbuf:	ds	80H		; Buffer for command parsing.
cmfcb:	ds	2		; Pointer to FCB.
cmfcb2:	ds	2		; Pointer to position in FCB.
cmcptr:	ds	2		; Pointer for next char input.
cmdptr:	ds	2		; Pointer into the command buffer.
cmkptr:	ds	2		; Pointer to keyword.
cmsptr:	ds	2		; Place to save a pointer.

oldsp:	ds	2		; Room for old system stack.
	ds	40H		; Room for 32 levels of calls.
stack:	ds	2
eoflag:	ds	1		; EOF flag; non-zero on EOF.
filflg:	ds	1		; Non-zero when nothing in DMA buffer.
logflg:	db	0		; Flag for a log file.
ecoflg:	db	0		; Local echo flag (default off).
escflg:	db	0		; Escape flag (start off).
IF vector
vtvflg:	db	1		; Flag for VECTOR VT52 emulation.
vctccc:	ds	1		; Storage for reversing row and column.
ENDIF				;vector

IF NOT (robin OR gener OR rainbo OR dmII)
vtflg:	db	1		; VT52 emulation flag (default on).
ENDIF				;NOT (robin OR gener OR rainbo OR dmII)

;IF robin
;gppflg:db	0		; Flag whether using comm port (0) or
;				; general port (1)
;ENDIF 				;robin

IF brain
flwflg:	db	1		; File warning flag (default on).
ENDIF				;brain

IF NOT brain
flwflg:	db	0		; File warning flag (default off).
ENDIF				;NOT brain

ibmflg:	db	0		; IBM flag (default off).
cpmflg:	db	0		; File was created by CPM.
parity:	db	defpar		; Parity.
escchr:	db	defesc		; Storage for the escape character.
chrcnt:	ds	1		; Number of chars in the file buffer.
filcnt:	ds	1		; Number of chars left to fill.
outpnt:	ds	2		; Position in packet.
bufpnt:	ds	2		; Position in file buffer.
filerc:	ds	1		; File record count.
fileex:	ds	1		; File extent. 
fcbptr:	ds	2		; Position in FCB.
datptr:	ds	2		; Position in packet data buffer.
cbfptr:	ds	2		; Position in character buffer.
pktptr:	ds	2		; Poistion in receive packet.
size:	ds	1		; Size of data from gtchr.
spsiz:	db	dspsiz		; Send packet size.
rpsiz:	db	drpsiz		; Receive packet size.
stime:	db	dstime		; Send time out.
rtime:	db	drtime		; Receive time out.
spad:	db	dspad		; Send padding.
rpad:	db	drpad		; Receive padding.
spadch:	db	dspadc		; Send padding char.
rpadch:	db	drpadc		; Receive padding char.
seol:	db	dseol		; Send EOL char.
reol:	db	dreol		; Receive EOL char.
squote:	db	dsquot		; Send quote char.
rquote:	db	drquot		; Receive quote char.
pktnum:	ds	1		; Packet number.
numpkt:	ds	2		; Total number of packets sent.
numrtr:	ds	2		; Total number of retries.
numtry:	ds	1		; Number of tries on this packet.
oldtry:	ds	1		; Number of tries on previous packet.
state:	ds	1		; Present state of the automaton.
packet:	ds	4		; Packet (data is part of it).
data:	ds	5AH		; Data and checksum field of packet.
recpkt:	ds	60H		; Receive packet storage (use the following).
filbuf:	ds	60H		; Character buffer.
temp1:	ds	1		; Temporary storage.
temp2:	ds	1
temp3:	ds	1
temp4:	ds	1
argblk:	ds	20H		; Used for subroutine arguments.
fcbnum:	ds	1		; Number of FCB's left in the list.
fcbblk:	ds	maxfil*10H	; Used for a list of FCB's.

IF osbrn1
osbaud:	db	1		; Baud rate: 0=300, non-0=1200
osmove:
osflag	equ	0EF08H		; Osborne 1 Bank-2 flag
OSLDST	EQU	ostop-osmove+$
	DI
	OUT	0
	LDA	osprts	; Read the status port
	OUT	1
	EI
	ret
OSSTST	equ	ostop-osmove+$
	DI
	OUT	0
	STA	osprts	; Write the control port
	jmp	osstex
OSLDDA	equ	ostop-osmove+$
	DI
	OUT	0
	LDA	osport
	OUT	1
	EI
	ret
OSSTDA	equ	ostop-osmove+$
	DI
	OUT	0
	STA	osport
osstex	equ	ostop-osmove+$
	OUT	1
	mvi	a,1
	sta	osflag
	EI
	ret
osmct	equ	$-osmove
ENDIF
	END
