;THIS PROGRAM, CONSISTING OF A PROM SECTION OF SUBROUTINES & MAINLINE
;TASKS AND A RAM SECTION OF BUFFERS, GENERATES AND DECODES MORSE CODE
;AS WELL AS RADIO TELETYPE (RTTY).

;THE DECODING SECTION IS DESIGNED TO BE SELF TRACKING
;AS TO CHANGING SPEEDS.  DUE TO THIS SELF TRACKING
;FEATURE, A FEW ILLEGAL CODES MAY BE DECODED AS THE
;PROGRAM ATTEMPTS TO LOCK ONTO THE INPUT CODE SPEED.

;THIS PROGRAM IS DESIGNED TO RUN ON THE INTEL 8080 BASED
;BSR MODULE MANUFACTURED BY DIGITAL EQUIPMENT CORPORATION.


;WRITTEN 1977 BY BRUCE FILGATE IN PARTIAL FULFILLMENT
;FOR THE MASTERS THESIS AT WORCESTER POLYTECHNICAL INSTITUTE.




;MORSE CODE SYMBOL WEIGHTING IS 1 DASH TO 3 DOTS.


;JUST A FEW WORDS ABOUT THE STACK STRUCTURE.....
	;THE STACKS USE THE FIRST LOCATION AS A COUNT OF THE
	;NUMBER OF OTHER USED LOCATIONS IN THE STACK.  UNLIKE
	;THE MAIN PROGRAM STACK, THESE STACKS START AND PROCEED
	;UPWARDS IN MEMORY ADDRESS SPACE AND ARE FIFO NOT LIFO.

;THE COMMAND REGISTER FOR THE USART AT ADDRESS 20001 (40 001)
;USES BIT 1 (DATA TERMINAL READY) AS THE CODE OUTPUT LINE
;AND BIT 7 (DATA SET READY) AS THE CODE INPUT LINE.  THE USART
;PROPER, IS USED FOR THE RTTY I/O.


;KEY SENSE FOR CODE (AND RTTY) INPUT AND OUTPUT IS GROUND FOR KEY DOWN
	;CONDITION AND LOGIC HIGH FOR THE KEY UP CONDITION.


;*******************************************************
;
; PROGRAM SHOULD BE STARTED AT START
;
;*******************************************************


;THE TERMINAL WILL TYPE A "?" WHENEVER A BUFFER
	;OVERFLOW IS CAUSED BY THE USER.  THE CHARACTER
	;THAT WOULD HAVE CAUSED THE OVERFLOW IS TRAPPED
	;AND DELETED.


;NORMALLY THE KEYBOARD DATA IS TRANSMITTED OUT TRANSLATED IN MORSE
;CODE, BUT THE ALT MODE (ESC) KEY MAY BE USED TO ENTER SPECIAL COMMANDS.
;THE ALT MODE IS FOLLOWED BY ONE OF THE FOLLOWING CHARACTERS TO
;ENTER THE REQUIRED FUNCTION:
;	1=INPUT AND TRANSLATE MORSE CODE, OR RTTY UNTIL, ^C IS TYPED ON CONSOLE
;	2=PRINT & OPEN "STATION" BUFFER FOR A COMMAND
;	3=PRINT & OPEN MESSAGE BUFFER "A" FOR A COMMAND
;	4=PRINT & OPEN MESSAGE BUFFER "B" FOR A COMMAND
;	5=PRINT & OPEN MESSAGE BUFFER "C" FOR A COMMAND
;		ONCE ENTERED THE BUFFER OPERATIVES ARE:
;			L FOLLOWED BY NEW TEXT TERMINATED WITH ESC TO LOAD TEXT
;			S TO XMIT THE BUFFER IN CODE
;	6=GENERATE A QUIZ BY SENDING RANDOM CHARACTERS IN CODE AND WAITING
;		FOR A KEYBOARD ANSWER.  USE ^C TO EXIT FROM THIS MODE.
;		THE RANDOM CHARACTERS ARE CHOSEN FROM THE CONTENTS OF
;		THE "A" MESSAGE BUFFER.  IF THE INCORRECT RESPONSE
;		IS TYPED THE PROGRAM RESPONDS IN CODE WITH "ERROR"
;		FOLLOWED BY A REPEAT OF THE MISSED CHARACTER.
;	7=GENERATE RANDOM FIVE CHARACTER CODE GROUPS AND TYPE THEM OUT ON
;		THE TERMINAL.  THE CHARACTERS A GENERATED FROM THE
;		CONTENTS OF THE "A" MESSAGE BUFFER.
;	8=TRANSMIT "STATION" BUFFER CONCATENATED WITH MESSAGE BUFFER "B"
;	9=TRANSMIT "STATION" BUFFER CONCATENATED WITH MESSAGE BUFFER "C"
;	0=LOG THE COMPLETED QSO
;	-=TRY TO FIND "STATION" IN THE LOG
;	C=MORSE CODE MODE (NOT RTTY MODE)
;	G=GAIN SPACE FOR MORE LOG ENTRIES BY DOING A COMPRESS.  PRIOR TO
;		COMPRESS, THE PART OF THE LOG WHICH HAS NOT BEEN PREVIOUSLY
;		COMPRESSED, IS PRINTED OUT ON THE TERMINAL.
;	M=MAINTENANCE BRANCH TO MDP VIA BRKX
;	P=PRINT OUT THE ENTIRE LOG
;	R=ENTER RTTY MODE (NOT MORSE CODE MODE)
;	S=SET THE TIME WITH THE NEXT FOUR CHAR (HHMM)
;	T=PRINT OUT THE CURRENT TIME
;	W=LOAD BAUD CONSTANT FOR WPM OUTPUT.  THE COMMAND IS THE LETTER
;		W FOLLOWED BY ONE OF THE FOLLOWING SYMBOLS DEPENDING ON THE
;		SPEED DESIRED:
;			SPACE	120 WPM
;			!	89
;			"	63
;			#	48
;			$	44
;			%	37
;			'	27
;			)	22
;			+	18
;			/	14
;			3	12
;			>	7.6
;			?	7.2
;
;	X=XMIT THE "A" MESSAGE BUFFER UNTIL ^C
;	Z=ZAP (CLEAR) THE LOG AREA BUFFER
;
;
;THE DELETE (RUBOUT) KEY SERVES TWO FUNCTIONS DEPENDING
;ON WHETHER THE USER IS LOADING THE DATA BUFFER OR TYPING
;DATA TO BE IMMEDIATLY TRANSMITTED IN CODE.  WHEN IN THE
;MESSAGE BUFFER LOADING MODE, THE DELETE WILL REMOVE
;ONE CHARACTER AT A TIME FROM THE BUFFER UNTIL THE BUFFER
;IS EMPTY.  WHEN THE CHARACTERS ARE BEING TRANSMITTED AS
;THEY ARE TYPED, THE DELETE KEY WILL GENERATE THE ERROR
;CODE (EIGHT DOTS).
;
;
;	# IS USED AS THE PROMPT FOR THIS PROGRAM
;
;
;

;BUFFER SIZE SET UP
	MSGSZ=377	;MESSAGE HOLDING BUFFERS
	BUFOUT=60	;CODE OUTPUT
	BUFSKY=100	;KEYBOARD
	BUFSPN=60	;PRINTER

;CONSTANTS, ANY OF THESE MAY BE MODIFIED BY EDITING AND REASSEMBLING THE PROGRAM
	TUSART=10000	;TTY ADDRESS FOR CONSOLE
	RUSART=20000	;RTTY ADDRESS FOR BAUDOT/MORSE
	WIDTH=117	;PRINTER WIDTH IN OCTAL
	FILL=4		;# OF FILL CHARS NEEDED FOR CR/LF
	FILCHR=0	;ASCII FILL CHAR USED FOR CR/LF
	ERCHAR=77	;CONSTANT FOR ERROR CHAR (ASCII "?"=77)
	ESC=33		;ENTER COMMAND MODE (TV50 ESC=175,LA36=33)
	K=113		;SENT IN CODE WHEN QUIZ ROUTINE IS READY
	ESCSYM=44	;ECHO A $ FOR ESC
	QUEST=77	;QUESTION MARK FOR BAD COMMAND
	DELETE=177	;CHAR THAT REPRESENTS THE DELETE
	DELSYM=134	;PRINTABLE CHAR FOR A DELETE
	ETX=3		;CONTROL C EXIT TO STRT
	BLANK=40	;ASCII SPACE CONSTANT
	MEMEND=77777	;LAST MEMORY LOCATION (16K RAM AT PRESENT)
	LTRS=37		;BAUDOT SHIFT
	FIGS=33		;BAUDOT SHIFT



;EXTRA INSTRUCTIONS TO MAKE LIFE EASIER
	.MACRO	STATUS	;GET TTY STATUS
	LDA	TUSART+1
	.ENDM

	.MACRO	PRINT	;PRINT THE A REG
	STA	TUSART
	.ENDM


	.MACRO	READ	;FETCH THE KEYBOARD TO A
	LDA	TUSART
	.ENDM


	.MACRO	SENSE	;SET STATUS FLAGS FOR CODE INPUT STATUS
	LDA	RUSART+1	;GET BIT
	ANI	200		;KEEP THE RELEVANT BIT
	.ENDM



	.MACRO	OUTPUT	;SET THE CODE OUTPUT LINE
	STA	RUSART+1
	.ENDM




	.=2000	;SET ON NEXT PROM ABOVE MDP
	;START UP TIME HOUSEKEEPING
START:	XRA	A	;A=0
	STA	MSGABF	;CLEAR THE MESSAGE BUFFERS
	STA	MSGBBF
	STA	MSGCBF
	STA	STACAL
	LXI	H,LOGSTR	;CLEAR THE LOG ENTRY TABLES
	SHLD	LOGCMP		;START OF NON-COMPRESSED LOG
	MVI	M,<15>		;CR TO HELP IN LOG LOOK UP
	INX	H
	SHLD	LOGPNT
	MOV	M,A		;STORE OUT A NULL BYTE FOR END OF LOG
	MVI	A,35
	STA	BAUD	;SET OUTPUT BAUD AT ABOUT 15 WPM
	STA	BAUDI		;LIKEWISE WITH INPUT BAUD
	STA	RTTYMD		;START UP MODE IS MORSE (NON-ZERO)
	LXI	H,RUSART+1	;SET UP RTTY/MORSE USART
	MVI	M,302	;2 STOP BITS, 5 DATA BITS, 16*CLK@45 BAUD (60 WPM)
;RESTART FOR CONTROL C
START2:	LXI	SP,STACK	;FIX STACK POINTER
	MVI	A,5		;CLEAR THE MORSE CODE OUTPUT DRIVER
	OUTPUT
	XRA	A
	STA	KYFIFO	;CLEAR THE KYBD CHAR COUNT
	STA	OTFIFO	;CLEAR THE OUTPUT BUFFER
	STA	TWIDTH	;SET FOR CR INITIALIZATION
	STA	PNFIFO	;INITIALIZE THE PRINTER CHAR CNT
CLRMD:	LXI	H,CMMND	;COMMAND MODE OR DATA MODE
	MVI	M,0	;MAKE IT DATA MODE
1$:	CALL	IOALL	;OVERLAY I/O
	MVI	B,<15>	;CR
	CALL	PPAK
	JNZ	1$	;RETRY IF ERROR
2$:	CALL	IOALL	;OVERLAY I/O
	MVI	B,'#	;SET UP B REG TO PROMPT
	CALL	PPAK	;PRINT THE PROMPT
	JNZ	2$	;RETRY IF ERROR
;FALL THROUGH INTO MAIN PROGRAM LOOP


;MONITOR ENTRY AND SUPERVISOR MAIN TASK
RESTRT:	CALL	IOALL	;CHECK PENDING I/O ON KYBRD,PNTR,CODE OUT
	LDA	CMMND		;TEST THE MODE BYTE
	ORA	A	;SET FLGS
	JNZ	CMMNDR		;ENTER COMMAND MODE
	CALL	IDLE		;NON COMMAND CHARACTER FEEDTHROUGH
	JMP	RESTRT		;AND LOOP (?) ALONG



;ASCII TABLE OF DATA
ASCTAB:	.ASCII	/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
	.ASCII	/1234567890/
	.ASCII	;-.,?/:()'";
	.ASCII	/;/
	.BYTE	15	;END OF MESSAGE(CR/LF)
ASCEND:	.BYTE	12	;END OF WORK(CR/LF)


	;MORSE TABLE:1=DASH,0=DOT,WITH A 1 TO END THE CHAR
MORTAB:	.BYTE	140	;A
	.BYTE	210	;B
	.BYTE	250	;C
	.BYTE	220	;D
	.BYTE	100	;E
	.BYTE	50	;F
	.BYTE	320	;G
	.BYTE	10	;H

	.BYTE	40	;I
	.BYTE	170	;J
	.BYTE	260	;K
	.BYTE	110	;L
	.BYTE	340	;M
	.BYTE	240	;N
	.BYTE	360	;O
	.BYTE	150	;P

	.BYTE	330	;Q
	.BYTE	120	;R
	.BYTE	20	;S
	.BYTE	300	;T
	.BYTE	60	;U
	.BYTE	30	;V
	.BYTE	160	;W
	.BYTE	230	;X

	.BYTE	270	;Y
	.BYTE	310	;Z
	.BYTE	174	;1
	.BYTE	74	;2
	.BYTE	34	;3
	.BYTE	14	;4
	.BYTE	4	;5
	.BYTE	204	;6

	.BYTE	304	;7
	.BYTE	344	;8
	.BYTE	364	;9
	.BYTE	374	;0

	.BYTE	206	;-
	.BYTE	126	;.
	.BYTE	316	;,
	.BYTE	62	;?
	.BYTE	224	;(SLASH)
	.BYTE	342	;:
	.BYTE	266	;(
	.BYTE	266	;)
	.BYTE	172	;'
	.BYTE	112	;"
	.BYTE	252	;;
	.BYTE	124	;END OF MESSAGE(CR/LF)
MOREND:	.BYTE	26	;END OF WORK(CR/LF)

;RTTY TABLE, 5 LSB ARE DATA; MSB=1 IF IN LTRS, =0 IF FIGS
RTYTAB:	.BYTE	203	;A
	.BYTE	231	;B
	.BYTE	216	;C
	.BYTE	211	;D
	.BYTE	201	;E
	.BYTE	215	;F
	.BYTE	232	;G
	.BYTE	224	;H

	.BYTE	206	;I
	.BYTE	213	;J
	.BYTE	217	;K
	.BYTE	222	;L
	.BYTE	234	;M
	.BYTE	214	;N
	.BYTE	260	;O
	.BYTE	226	;P

	.BYTE	227	;Q
	.BYTE	212	;R
	.BYTE	205	;S
	.BYTE	220	;T
	.BYTE	207	;U
	.BYTE	266	;V
	.BYTE	223	;W
	.BYTE	235	;X

	.BYTE	225	;Y
	.BYTE	221	;Z
	.BYTE	027	;1
	.BYTE	023	;2
	.BYTE	001	;3
	.BYTE	012	;4
	.BYTE	020	;5
	.BYTE	025	;6

	.BYTE	007	;7
	.BYTE	006	;8
	.BYTE	030	;9
	.BYTE	026	;0

	.BYTE	003	;-
	.BYTE	034	;.
	.BYTE	034	;,
	.BYTE	031	;?
	.BYTE	035	;/
	.BYTE	016	;:
	.BYTE	017	;(
	.BYTE	022	;)
	.BYTE	015	;'
	.BYTE	021	;"
	.BYTE	066	;;
	.BYTE	010	;CR
RTYEND:	.BYTE	002	;LF


;SUBROUTINE TO PUT DATA IN A GENERAL STACK
	;STACK POINTER IN H&L, DATA IN B, BUFFER SIZE IN C
	;RETURNS WITH A=0 IF NO ERROR, =NON ZERO IF ERROR
ENTPAK:	MOV	A,M	;CHAR COUNT TO A
	DCR	C	;COMPUTE CHARACTER LOCATIONS IN BUFFER
	CMP	C	;DON'T OVERFLOW THE BUFFER
	JZ	ERROFL	;FULL...
	ADI	1	;BUMP THE COUNT
	MOV	M,A	;CHAR COUNT UPDATE TO MEM
	ADD	L	;LOW POINTER ADDED TO A
	MOV	L,A	;GET L VALUE UPDATED TO L REG
	JNC	OK	;IF A CARRY, FIX THE H
	INR	H	;FIX H REG
OK:	MOV	M,B	;CHAR TO MEMORY
	XRA	A	;CLEAR THE A REG
	RET		;DONE
ERROFL:	ADI	1	;SET A REG NON ZERO ERR RETURN
	RET		;SYSTEM ERROR, SYSTEM MUST FIX!!!!



;POP SUBROUTINE: ENTERED WITH POINTER IN H&L, SIZE IN B
POP:	MOV	A,M	;GET CHAR COUNT TO A REG
	SUI	1	;DECREMENT
	RC		;IF BUFFER IS EMPTY, FORGET POP
	MOV	M,A	;RESTORE THE NEW COUNTER TO BUFFER
	JMP	POPY	;GET INTO POPLOP LOOP

	;LOOP FOR POP
POPLOP:	INX	H	;POINT AT CHAR TO POP
	MOV	C,M	;GET CHAR TO C REG
	DCX	H	;POINT TO NEW LOCATION
	MOV	M,C	;PUT CHAR IN MEMORY
	MOV	A,B	;B TO A REG
	SUI	1	;SUBTRACT 1
POPY:	RZ		;DONE?
	MOV	B,A	;RESTORE B REG
	INX	H	;RECOVER FROM THE DECREMENT POSITION
	JMP	POPLOP	;NEXT PAIR POP



;SUBROUTINE TO WAIT A UNIT CODE TIME, DESTROYS A,B,C
TICK:	LXI	H,BAUD	;POINT AT CONST
	MVI	C,250	;MULTIPLIER CONSTANT
WAIT2:	MOV	B,M	;CONST TO B
WAIT1:	DCR	B	;COUNT IT DOWN DELAY
	JNZ	WAIT1
	DCR	C	;MULTIPLY IT
	JNZ	WAIT2
	CALL	IOTERM	;OVERLAP WITH  TERMINAL I/O
	RET		;DELAY OVER!!!!



;DELAY, USED FOR 8 SLICE DECODING OF INPUT CODE
TICKI:	LXI	H,BAUDI	;POINT AT CONSTANT
	MVI	C,25	;8 TIMES FASTER THAN TICK
	JMP	WAIT2	;FINISH TICKI IN TICK ROUTINE




;SUBROUTINE TO GENERATE A DOT AND POST SPACE, DESTROYS A,B,C,H,L
DOT:	MVI	A,2	;SET KEY DOWN
	OUTPUT		;TURN ON THE KEY (DOWN)
	JMP	FINDOT	;FINISH THE DOT IN THE DASH ROUTINE



;SUBROUTINE GENERATES DASH ITS POST SPACE, DESTROYS A,B,C,H,L
DASH:	MVI	A,2	;SET KEY DOWN
	OUTPUT		;KEY DOWN
	CALL	TICK	;DASH
	CALL	TICK
FINDOT:	CALL	TICK	;ENTERED HERE TO FINISH A DOT
	XRA	A	;CLEAR THE A REG
	OUTPUT		;KEY UP
	CALL	TICK
	RET



;MONITOR TASK SUBROUTINE FOR HANDLING COMMANDS FROM THE KEYBOARD
CMMNDR:	CALL	UNPAK	;GET CHAR FROM KEYBOARD
	JZ	CMMNDR	;IF NO CHAR, WAIT...
	CPI	ESC	;WAS IT ANOTHER ESC?
	JZ	CLRMD	;EXIT ON ESC
	CPI	'1	;RECEIVER ENABLE?
	JZ	INPREC	;SET FOR INPUT OF RTTY OR MORSE
	CPI	'2	;OPEN "STATION" CALL BUFFER
	JZ	STABUF
	CPI	'3	;BUFFER "A" OPERATION?
	JZ	ABUF
	CPI	'4	;BUFFER "B" OPERATION?
	JZ	BBUF
	CPI	'5	;BUFFER "C" OPERATION?
	JZ	CBUF
	CPI	'6	;WAS IT A QUIZ COMMAND?
	JZ	QUIZ	;YES, ENTER THE QUIZ MODE
	CPI	'7	;WAS IT RANDOM QUIZ COMMAND?
	JZ	RQUIZ	;YES, ENTER THE RQUIZ MODE
	CPI	'8	;XMIT "STATION" THEN "B"
	JZ	MSGSTB
	CPI	'9	;XMIT "STATION" THEN "C"
	JZ	MSGSTC
	CPI	'0	;LOG QSO
	JZ	LOG
	CPI	'-	;FIND LOG ENTRY
	JZ	FIND
	CPI	'C	;MORSE CODE MODE SET UP?
	JZ	CODEST	;SET UP MORSE MODE
	CPI	'G	;GAIN SPACE BY COMPRESSING LOG
	JZ	COMPRS
	CPI	'M	;MAINT BRANCH
	JZ	774	;TO BRK2 IN MDP
	CPI	'P	;PRINT OUT THE LOG
	JZ	GETLOG
	CPI	'R	;SET UP RTTY MODE?
	JZ	RTTYST	;SET UP FOR RTTY
	CPI	'S	;SET THE CLOCK
	JZ	SCLOCK
	CPI	'T	;PRINT OUT THE TIME
	JZ	CLOCK
	CPI	'W	;WAS IT A NEW WPM CONSTANT?
	JZ	WPM	;YES, LOAD NEXT CHAR AS THE CONST
	CPI	'X	;WAS IT A XMIT TEST?
	JZ	TEST	;YES, SEND THE BUFFER UNTIL ESC IS TYPED
	CPI	'Z	;Z TO ZAP, CLEAR THE LOG
	JZ	CLRLOG
;IF HERE A BAD COMMAND
	MVI	B,QUEST	;QUESTION MARK
	CALL	PPAK	;TO THE PRINTER FIFO
	JMP	CMMNDR	;TRY FOR A VALID COMMAND CHAR
ABUF:	LXI	H,MSGABF	;A BUFFER
	MVI	C,MSGSZ		;SIZE OF BUFFER
	JMP	BUFDO		;DO OPERATION
BBUF:	LXI	H,MSGBBF	;B BUFFER
	MVI	C,MSGSZ		;SIZE OF BUFFER
	JMP	BUFDO
CBUF:	LXI	H,MSGCBF	;C BUFFER
	MVI	C,MSGSZ		;SIZE OF BUFFER
	JMP	BUFDO
STABUF:	LXI	H,STACAL	;"STATION" BUFFER
	MVI	C,7		;SIZE OF BUFFER (6 CHAR + COUNTER)
BUFDO:	PUSH	H		;SAVE POINTER
	PUSH	B
;PRINT THE CURRENT BUFFER
	XRA	A	;SET SOH=0
	STA	SOH
	CALL	DMPSUB	;PRINT
1$:	CALL	UNPAK		;BUT WHAT TO DO?
	JZ	1$		;WAIT FOR COMMAND
	POP	B
	POP	H
	CPI	'L	;LOAD?
	JZ	LDNXT
	CPI	'S	;XMIT?
	JZ	2$
	PUSH	H
	PUSH	B
	MVI	B,QUEST	;QUEST MARK
	CALL	PPAK	;FOR BAD COMMAND
	JMP	1$
2$:	CALL	SNDNX	;XMIT
	JMP	CLRMD	;CLEAR COMMAND MODE

;SET UP RTTY VS MORSE CODE MODE
RTTYST:	XRA	A	;ENTERED HERE IF RTTY MODE
	LXI	H,RUSART+1	;SET UP SERIAL MODES
	MVI	M,5		;ENABLE TRANS & REC
	JMP	STRTTY
CODEST:	MVI	A,1	;ENTERED HERE IF CODE MODE
STRTTY:	STA	RTTYMD	;STORE MODE BYTE
	JMP	CLRMD


;XMIT "STATION" THEN BUFFER B
MSGSTB:	LXI	H,STACAL	;XMIT "STATION"
	CALL	SNDNX
	LXI	H,MSGBBF	;XMIT B
	CALL	SNDNX
	JMP	CLRMD

;XMIT "STATION" THEN BUFFER C
MSGSTC:	LXI	H,STACAL	;XMIT "STATION"
	CALL	SNDNX
	LXI	H,MSGCBF	;XMIT C
	CALL	SNDNX
	JMP	CLRMD



;SUBROUTINE PRINT & XMIT BUFFER (POINTED TO BY HL) IN CODE
SNDNX:	PUSH	H	;SAVE FOR XMIT
	PUSH	B
	XRA	A	;PRINT
	STA	SOH
	CALL	DMPSUB	;PRINT
	POP	B
	POP	H
	MVI	A,1	;CODE SET UP
	STA	SOH
	CALL	DMPSUB	;XMIT THE MESSAGE BUFFER
	RET		;EXIT



;ROUTINE TO LOAD THE MESSAGE BUFFER POINTED TO BY HL, SIZE IN C
LDNXT:	MVI	M,0	;ZERO CHAR COUNT
	PUSH	H
	PUSH	B
1$:	CALL	UNPAK	;GET KEYBOARD CHAR
	JZ	1$	;WAIT
	POP	B
	POP	H
	CPI	ESC	;END OF INPUT?
	JZ	CLRMD	;EXIT
	PUSH	H
	PUSH	B
	CPI	DELETE	;RUB OUT?
	JNZ	2$
	MOV	A,M	;GET CHAR COUNT
	ORA	A	;SET FLAGS
	JZ	1$	;NOTHING TO DELETE!
	DCR	M	;DELETE ONE CHAR
	JMP	1$
2$:	MOV	B,A	;CHAR TO B FOR ENTPAK, SIZE IN C
	CALL	ENTPAK
;TEST FOR BUFFER OVERFLOW
	MVI	B,ERCHAR	;TELL USER IF OVERFLOW
	CNZ	PPAK		;BUT ONLY IF ERROR
	JMP	1$	;LOOP



;SUBROUTINE FOR USER ERROR INDICATION
	;BYPASSES CHARACTER POSITION COUNTER FOR THE TERMINAL
WHOOPS:	STATUS		;YES, GET PRINTER STATUS
	ANI	1	;TBMT MASK
	JZ	WHOOPS	;WAIT
	MVI	A,ERCHAR	;SET ERROR INDICATION
	PRINT
	RET


;SUBROUTINE TO MOVE THE MESSAGE BUFFER CONTENTS TO LOCATION
;DEFINED BY THE SOH LOCATION.  0=PRINTER    1=TRANSMITTER
;BUFFER ADDRESS IN HL
DMPSUB:	XRA	A
	CMP	M	;A MESSAGE STORED?
	RZ		;NO
	MOV	C,M	;YES, CHAR COUNT TO C REG
4$:	INX	H	;POINT AT NEXT CHAR
5$:	MOV	B,M	;GET CHAR TO REG B
	LDA	SOH	;CHECK MODE
	ORA	A	;SET FLAGS
	PUSH	H	;SAVE POINTERS
	PUSH	B
	JNZ	1$	;XMIT MODE
	CALL	PPAK	;PRINT MODE
	JMP	2$
1$:	LXI	H,OTFIFO	;POINT AT XMIT BUFFER
	MVI	C,BUFOUT	;BUFFER SIZE SET UP
	CALL	ENTPAK		;XMIT
2$:	JNZ	3$		;ERROR
	POP	B	;RESTORE POINTERS
	POP	H
	DCR	C	;UPDATE CHAR COUNT
	JNZ	4$
	RET
3$:	CALL	IOALL	;CLEAR IO ERR
	POP	B
	POP	H
	JMP	5$


;QUIZ ROUTINE TO SEND RANDOM CHARACTERS FROM THE MESSAGE BUFFER
; AND THEN WAIT FOR A KEYBOARD RESPONSE.  IF THE KEYBOARD RESPONSE
;IS INCORRECT THE CHARACTER IS REPEATED.  ^C WILL CAUSE
; AN EXIT FROM THIS ROUTINE.
QUIZ:	LXI	H,RTTYMD	;SET FOR MORSE NOT RTTY
	MVI	M,1		;SO MODE IS NON ZERO
	;OUTPUT A K TO TELL USER THE QUIZ IS IN PROGRESS
	MVI	A,K	;CHAR TO A REG
QZAGN1:	LXI	H,QTEMP	;PUT IN SAVE LOCATION
			;IN CASE THE ANSWER IS INCORRECT
	MOV	M,A	;AND THE LETTER MUST BE REPEATED.
QZAGN:	CALL	OUTPAK	;TO CODE BUFFER
QUIZWT:	CALL	IOALL	;OVERLAY I/O
	CALL	UNPAK	;ANY RESPONSE YET?
	JNZ	NXTRAN	;YES, GET THE ANSWER
	LXI	H,RANCHR	;NO, UPDATE THE RANDOM POINTER
	INR	M	;+1
	JMP	QUIZWT	;LOOP FOR A RESPONSE


	;USER HAS RESPONDED
NXTRAN:	LXI	H,QTEMP	;TEST THE RESPONSE
	CMP	M	;SAME CHARACTER?
	JNZ	CHRERR	;NO, REPEAT THE CHAR
	CALL	NXTCHR	;YES, DO UP THE NEXT CHARACTER
	JMP	QZAGN1	;RUN WITH THE NEW CHAR
CHRERR:	MVI	A,DELETE	;NO, ERROR BY USER SO TELL HIM
	CALL	OUTPAK
	MVI	B,DELSYM	;BACKSLASH ON THE TERMINAL
	CALL	PPAK
	MVI	A,BLANK	;SPACE IN TIME
	CALL	OUTPAK
	LXI	H,QTEMP	;REPEAT CHAR
	MOV	A,M	;RESEND THE MISSED CHARACTER
	JMP	QZAGN


;ROUTINE TO SEND RANDOM 5 CHARACTER CODE GROUPS GENERATED FROM
;CHARACTERS IN THE MESSAGE BUFFER.
RQUIZ:	LXI	H,RTTYMD	;SET TO MORSE NOT RTTY
	MVI	M,1	;MORSE IS NON ZERO MODE
	LXI	H,GRPCNT	;POINT AT GROUP OF 5 COUNTER
	MVI	M,WIDTH/6	;# OF GROUPS BEFORE A LF
NEWGRP:	LXI	H,CHRCNT	;POINT AT CHAR/GROUP COUNTER
	MVI	M,5	;# OF CHARACTERS IN GROUP

;THIS SEGMENT OF CODE GENERATES A RANDOM NUMBER BY ADDING SUCCESIVELY
;ONE ELEMENT OF THE SERIES 0,1,2,3......376,377,0,1 TO THE CURRENT
;RANDOM NUMBER MODULO 377 OCTAL.
RQZAGN:	LDA	RANCHR+1	;INDEX TO A REG
	INR	A	;+1
	STA	RANCHR+1	;SAVE NEW INDEX
	LXI	H,RANCHR	;POINT AT OLD RANDOM NUMBER
	ADD	M	;ADD TO INDEX FOR NEW RANDOM #
	MOV	M,A	;SAVE RANDOM NUMBER
	CALL	NXTCHR	;GENERATE THE NEXT CHARACTER
	STA	QTEMP		;SAVE IT
	CALL	OUTPAK	;CODE IT OUT
	CALL	OTPUT	;OVERLAY I/O
	LXI	H,QTEMP		;GET IT BACK
	MOV	B,M
	CALL	PPAK	;PRINT IT
	CALL	IOTERM	;OVERLAY TERMINAL I/O
	;DONE WITH A GROUP?
	LXI	H,CHRCNT	;POINT AT CHAR COUNTER
	DCR	M	;-1
	JNZ	RQZAGN	;NOT DONE, GET THE NEXT CHAR
	MVI	A,BLANK	;DONE WITH THE GROUP SO
	CALL	OUTPAK		;OUTPUT SOME FREE AIR
	CALL	OTPUT	;OVERLAY THE I/O
	MVI	B,BLANK	;ALSO DO IT
	CALL	PPAK	;ON THE PRINTER
	CALL	PNTR	;OVERLAY I/O
	LXI	H,GRPCNT	;DECREMENT THE GROUP COUNTER
	DCR	M	;-1
	JNZ	NEWGRP	;NOT DONE, GET THE NEXT GROUP
	MVI	B,<15>	;CR ON THE PRINTER
	CALL	PPAK	;TO PRINT BUFFER
	CALL	PNTR	;OVERLAY I/O
	JMP	RQUIZ	;LOOP UNTIL ^C


	;ROUTINE TO GET RANDOM CHAR FROM THE MESSAGE BUFFER, USED
	;BY BOTH QUIZ AND RQUIZ.
NXTCHR:	LDA	MSGABF	;CHECK CHAR COUNT NOT ZERO
	ORA	A	;SET FLAGS
	JNZ	1$	;OK, CONTINUE
	LXI	H,ERRMSG	;NO DATA, ERROR
	CALL	PRTMSG
	JMP	CLRMD
1$:	LDA	RANCHR	;GET RANDOM COUNTER
			;TO MAKE A RANDOM POINTER
	LXI	H,MSGABF	;POINT AT # OF CHAR IN MSSG BUFFER
NOKRAN:	CMP	M	;HAS RANCHR GOTTEN TOO LARGE?
	JZ	OKRAN	;MAYBE NOT...
	JC	OKRAN	;NO
	SUB	M	;YES, SUBTRACT
	JMP	NOKRAN	;AND TEST AGAIN
OKRAN:	ANA	A	;SET FLGS, ZERO?
	JNZ	AOKRAN	;NO
	ADI	1	;MAKE NON ZERO
AOKRAN:	ADD	L	;POINT AT A CHARACTER IN THE MSSG BUFFER
	MOV	L,A	;UPDATE L REG
	JNC	RAOK	;L OVERFLOW?
	INR	H	;YES, BUT FIXED IN H REG
RAOK:	MOV	A,M	;NEW CHAR TO A REG
	RET



;ROUTINE TO TEST OUTPUT, XMIT MESSAGE BUFFER "A" UNTIL ^C IS TYPED
TEST:	LXI	H,SOH	;SET UP FOR SEND MODE
	MVI	M,1
	LXI	H,MSGABF	;A BUFFER
	CALL	DMPSUB	;SEND THE BUFFER
	JMP	TEST	;AND LOOP....



;CODE TO LOAD A NEW WPM CONSTANT INTO BAUD
WPM:	CALL	UNPAK	;GET CHAR FROM KEYBOARD
	JZ	WPM	;WAIT FOR CHAR
	ANI	37	;MASK FOR 5 VALID BITS
	RLC		;MULTIPLY BY 2
	ORI	1	;SET THE LSB
	STA	BAUD	;CONSTANT TO BAUD LOCATION
	JMP	CLRMD	;EXIT TO MONITOR LOOP





;ROUTINE TO GET CHAR FROM KEYBOARD FIFO
	;RETURNS WITH CHAR IN A REG, A REG=0 IF NO CHAR
UNPAK:	CALL	IOALL	;TRY TO FINISH PENDING I/O
	LXI	H,KYFIFO	;POINT AT KEYBOARD STACK
	XRA	A	;CLEAR THE A REG
	ADD	M	;CHAR COUNT TO A REG
	RZ		;IF EMPTY, RETURN A REG=0
	INX	H	;POINT AT CHAR
	MOV	E,M	;GET CHAR TO E REG TEMP
	DCX	H	;POINT AT KEYBOARD FIFO
	CALL	POP	;OUT OF FIFO, RETURNS A=0
	ADD	E	;CHAR TO A REG AND FLGS
	RET		;RETURN WITH A REG=CHAR


;SUBROUTINE TO WAIT FOR THE TBMT FLAG
WAITMT:	STATUS		;GET TBMT FLAG
	ANI	1
	JZ	WAITMT	;WAIT....
	RET		;OK, HAVE TBMT





	;KEYBOARD HANDLER SUBROUTINE
KYBD:	STATUS		;GET THE SERIAL LINE STATUS
	ANI	2	;MASK   
	RZ		;NEXT TASK
	;PUT KEYBOARD CHARACTER IN KYBD FIFO
	READ		;GET CHAR FROM KEYBOARD TO A REG
	ANI	177	;GET RID OF ASCII PARITY BIT
	CPI	ETX	;CONTROL C
	JNZ	NETX	;NO
	CALL	WAITMT	;SEND OUT ^C
	MVI	A,'^
	PRINT
	CALL	WAITMT	;WAIT FOR TBMT
	MVI	A,'C
	PRINT
	CALL	WAITMT	;WAIT FOR TBMT
	JMP	START2	;GO RESTART FROM ALMOST ZERO
NETX:	LXI	H,KYFIFO	;POINT AT KYFIFO
	CPI	141	;LOWER CASE TRANSPOSE TO
	JC	STUFF	;UPPER CASE
	CPI	173	;BUT GET ONLY THE
	JNC	STUFF	;LOWER CASE
	SUI	40	;TRANSPOSE HERE
STUFF:	MOV	B,A	;CHAR TO B REG
	MVI	C,BUFSKY	;BUFFER SIZE TO C REG
	CALL	ENTPAK	;PUT CHAR IN BUFFER
	CNZ	WHOOPS	;IF OVERFLOW, TELL THE USER
	;FALL THROUGH AND RETURN IN NEXT ROUTINE







	;PUT CHAR IN PRINTER FIFO FROM B REG
	;RETURNS WITH A REG=0 IF NO ERROR,  =ERCHAR IF ERROR
PPAK:	LXI	H,PNFIFO	;POINT AT PNFIFO
	MVI	C,BUFSPN	;BUFFER SIZE TO C REG
	CALL	ENTPAK	;PUT CHAR IN FIFO
	RET

	;END OF THE KEYBOARD HANDLER TASK




;PRINTER HANDLER SUBROUTINE TASK
PNTR:	STATUS		;GET THE PRINTER STATUS
	ANI	1	;MASK FOR TBMT
	RZ		;IF BUSY, TRY SOMETHING ELSE
	LDA	TWIDTH	;CR/LF ?
	CPI	0
	JZ	1$	;AT 0, DO CR
	JP	PRT2	;>0, PRINT CHARS, IF ANY TO PRINT
	CPI	-1	;<0, DECODE FURTHER
	JZ	2$	;DO LF
	LXI	H,TFILL	;FILL CHARS REQUIRED?
	XRA	A
	ADD	M	;IF ZERO, DONE
	JZ	3$	;SO RESET
	DCR	M	;NOT DONE, BUT ONE LESS FILL
	MVI	A,FILCHR	;FILL CHAR
	JMP	PNT1
1$:	MVI	A,<15>	;CR
	JMP	PNT1
2$:	MVI	A,<12>	;LF
	JMP	PNT1
3$:	MVI	M,FILL	;RESET FILL COUNT
	LXI	H,TWIDTH	;RESET CHAR/LINE COUNT
	MVI	M,WIDTH
	RET
	MVI	M,WIDTH	;RESET PRINT POSITION COUNT
	RET
PRT2:	LXI	H,PNFIFO	;POINT AT CHAR COUNT
	XRA	A	;CLEAR THE A REG
	ADD	M	;CHAR COUNT TO A REG AND FLGS
	RZ		;NOTHING TO PRINT, NEXT TASK
;IF HERE THERE IS PRINTING TO BE DONE!!!!!!!
	;POINT AT CHAR TO PRINT AND PRINT IT
	INX	H
	MOV	E,M	;CHAR TO E REG TEMP
	;NOW UPDATE THE CHAR COUNT
	LXI	H,PNFIFO		;POINT AT CHAR COUNT
	CALL	POP	;RIPPLE THE FIFO
	MOV	A,E	;CHAR BACK TO A REG
	CPI	<12>	;IS IT A LF?
	JZ	INCRLF	;YES, INSERT A CRLF
	CPI	<15>	;IS IT A CR?
	JZ	INCRLF	;YES, INSERT A CRLF
	CPI	DELETE	;IS IT A DELETE?
	JZ	DEL	;YES, INSERT A BACKSLASH
	CPI	ESC	;IS IT AN ESC?
	JNZ	PNT1	;NO
	MVI	A,ESCSYM	;YES, SUBSTITUTE A PRINTABLE CHAR
PNT1:	LXI	H,TWIDTH	;UPDATE PRINT POSITION
	DCR	M	;-1
	PRINT		;PRINT THE CHAR
	RET		;DONE, PRINTED A CHAR
INCRLF:	LXI	H,TWIDTH	;SET FOR CRLF NEXT PASS
	MVI	M,0
	RET
DEL:	MVI	A,DELSYM	;SUBSTITUTE A PRINTABLE CHARACTER
	PRINT
	RET		;END TO THE PRINTER TASK
	



;THIS SUBROUTINE TRANSLATES A REG TO OUTPUT MODE AS DEFINED BY THE
;TABLE POINTED TO BY THE DE REG PAIR
	;COMPUTE THE DISPLACEMENT IN ASCTAB
XLATER:	LXI	H,ASCTAB	;POINT AT ASCTAB
THISIT:	CMP	M	;IS THIS THE CHAR?
	JZ	CONVT	;GO CONVERT THE CHAR
	INX	H	;TRY NEXT CHAR
	MOV	B,A	;SAVE THE CHAR IN B REG TEMPORARILY
	MVI	A,ASCEND/400	;GET HIGH LIMIT TO A FOR COMPARE
	CMP	H	;PAST END OF TABLE?
	JC	NTFUND	;PAST END OF TABLE AND NO MATCH
	MVI	A,ASCEND	;GET LOW LIMIT TO A FOR COMPARE
	CMP	L	;PAST END OF TABLE?
	JC	NTFUND	;PAST END OF TABLE AND NO MATCH
	;IF HERE, STILL IN TABLE.  TRY CONTENTS AGAIN.
	MOV	A,B	;RETURN CHAR TO A REG
	JMP	THISIT	;LOOP FOR NEXT TABLE ENTRY CHECK
CONVT:	MVI	A,ASCTAB	;TWOS COMPLEMENT TO BC
	CMA
	MOV	C,A
	MVI	A,ASCTAB/400
	CMA
	MOV	B,A	;1'S COMPL
	INX	B	;2'S COMPL
	DAD	B	;HL IS NOW RELATIVE DISPLACEMENT
	DAD	D	;HL IS NOW ABSOLUTE OUTPUT LOCATION
	MOV	A,M	;REPLACEMENT CHAR TO A REG
	RET		;CODE IN A REG RETURN
NTFUND:	MVI	A,200	;CHAR NOT FOUND LOAD OUT A 200
	RET		;ERROR RETURN




;THIS SUBROUTINE TRANSLATES A REG TO PRINT MODE
;ENTERED WITH SOURCE TABLE START ADDRESS IN DE, END ADDRESS IN BC
XLATR2:	LXI	H,MORTAB	;POINT AT MORTAB
THIS:	CMP	M	;IS THIS THE CHAR?
	JZ	MCONVT	;YES, GO CONVERT THE CHAR
	INX	H	;TRY NEXT CHAR
	PUSH	PSW	;SAVE CHAR TMP
	MOV	A,B	;GET HIGH LIMIT TO A FOR COMPARE
	CMP	H	;PAST END OF TABLE?
	JC	NTFND	;YES, WITH NO MATCH
	MOV	A,C	;GET LOW LIMIT TO A FOR COMPARE
	CMP	L	;PAST END OF TABLE?
	JC	NTFND	;YES, NO MATCH
	;IF HERE, STILL IN TABLE. TRY CONTENTS AGAIN
	POP	PSW	;RETURN CHAR TO A REG
	JMP	THIS	;LOOP FOR NEXT TABLE ENTRY CHECK
MCONVT:	MOV	A,E	;COMPUTE HL-DE+ASCTAB
	CMA		;TO GET ABSOLUTE ASCII TABLE ADDRESS
	MOV	E,A
	MOV	A,D
	CMA
	MOV	D,A	;1'S COMPLEMENT
	INX	D	;2'S COMPLEMENT
	DAD	D	;RELATIVE DISPLACEMENT
	MVI	D,ASCTAB/400
	MVI	E,ASCTAB
	DAD	D	;ABSOLUTE ADDRESS
	MOV	A,M	;REPLACEMENT CHAR TO A REG
	RET		;ASCII CODE IN A REG RETURN
NTFND:	POP	PSW	;RESTORE STACK
	MVI	A,BLANK	;CHAR NOT FOUND, LOAD OUT A SPACE
	RET		;ERROR RETURN







	;SUBROUTINE TASK TO XMIT IN RTTY OR MORSE
;XMIT OUTPUT CODE HANDLER
OTPUT:	LXI	H,OTFIFO	;POINT AT STACK
	XRA	A	;CLEAR THE A REG
	ADD	M	;CHAR COUNT TO A AND FLGS
	RZ		;NEXT TASK, IF NOTHING TO DO
	INX	H	;GET CHAR TO STACK TMP
	MOV	A,M
	PUSH	PSW
	;SET UP TO POP THE STACK
	LXI	H,OTFIFO	;POINT AT STACK
	CALL	POP	;POP THE STACK
	LDA	RTTYMD		;RTTY OR MORSE?
	ORA	A
	JZ	OTRTTY		;ZERO IS RTTY MODE
	POP	PSW	;GET THE DATA
	CPI	DELETE	;ERROR CHARACTER?
	JNZ	OTPUT1	;NO, GO TRANSLATE
	MVI	D,10	;YES, DO 8 DOTS
OTERR:	CALL	DOT	;1 DOT
	DCR	D	;-1 THE COUNT
	JNZ	OTERR	;NOT DONE....DO IT AGAIN
	JMP	OUTEND	;DONE, POP AND EXIT
OTPUT1:	LXI	D,MORTAB	;SET UP FOR MORSE CODE OUTPUT
	CALL	XLATER	;TRANSLATE
	MOV	D,A	;SAVE THE CHAR IN D REG
	CPI	200	;IS IT A BAD CHAR (OR A SPACE)?
	JNZ	GOODCH	;CHAR OK, SO DO IT UP RIGHT
	;IF HERE GENERATE A CHARACTER SPACE
	MVI	D,6	;SET UP FOR 7 UNITS DELAY(ONE UNIT IN CODE ELEMENT)
SPACE:	CALL	TICK	;WAIT ONE UNIT
	DCR	D	;DECREMENT THE UNIT COUNTER
	JNZ	SPACE	;LOOP UNTIL DONE
	JMP	OUTEND
GOODCH:	CPI	200	;IF A=200 THEN DONE
	JZ	OUTEND	;DONE!
	JNC	DSH	;DOT OR DASH?
	CALL	DOT	;YES A DOT, SO KEY OUT A DOT
	JMP	OTLOOP	;NEXT SYMBOL
DSH:	CALL	DASH	;MUST BE A DASH, SO KEY A DASH
OTLOOP:	MOV	A,D	;GET THE CHAR BACK TO THE A REG
	ANI	177	;THROW OUT THE USED BIT
	RLC		;ROTATE IN AN UNUSED BIT
	MOV	D,A	;SAVE THE NEW IMAGE IN D
	JMP	GOODCH	;LOOP FOR OTHER SYMBOLS
OUTEND:	CALL	TICK	;INTER LETTER SPACE
	CALL	TICK
	RET		;NEXT TASK
OTRTTY:	POP	PSW	;XMIT IN RTTY, GET CHAR
	LXI	D,RTYTAB	;SET UP FOR RTTY
	CALL	XLATER		;TO BAUDOT
	PUSH	PSW		;SAVE CHAR TMP
	ANI	200		;CHECK SHIFT
	LXI	H,LETFIG
	CMP	M		;CORRECT SHIFT?
	JZ	1$		;YES
	MOV	M,A		;NO, UPDATE SHIFT MEMORY
	JC	2$		;WAS LTRS, BUT NOW FIGS
	MVI	A,LTRS		;WAS FIGS, BUT NOW LTRS
	CALL	XMTRTY
	JMP	1$
2$:	MVI	A,FIGS
	CALL	XMTRTY
1$:	POP	PSW		;CHAR TO A
	CALL	XMTRTY
	RET
XMTRTY:	PUSH	PSW	;SAVE CHAR TMP, XMIT IN RTTY
1$:	LDA	RUSART+1	;STATUS OF
	ANI	1	;TBMT
	JZ	1$	;WAIT IF NEEDED
	POP	PSW
	STA	RUSART	;CHAR OUT ON USART SERIAL
	RET
	;END OF THE OUTPUT ENCODED DRIVE TASK SUBROUTINE




;KEYBOARD DECODER FOR NON COMMAND MODE
IDLE:	CALL	UNPAK	;SEE IF CHARACTER IS AVAILABLE
	RZ		;IF NO CHAR RDY, A=0 SO RETURN
	CPI	ESC	;IS CHARACTER AN ESC?
	JZ	IDLE1	;YES

	;ENTERED HERE TO PUT CHARACTER FROM A REGISTER INTO CODE BUFFER
OUTPAK:	LXI	H,OTFIFO	;OUTPUT IN CODE THEN SET UP FOR ENTPAK
	MOV	B,A	;DATA IN B REG
	MVI	C,BUFOUT	;SIZE IN C REG
	CALL	ENTPAK
	CNZ	WHOOPS	;BUFFER FULL, TELL USER
	RET		;DONE
IDLE1:	LXI	H,CMMND	;SET FOR COMMAND MODE
	MVI	M,1	;MODE=1
	RET





;SUBROUTINE TO SERVICE RECEIVER INPUT IN MORSE OR RTTY
INPREC:	LDA	RTTYMD	;RTTY OR MORSE?
	ORA	A
	JZ	INPRTY	;ZERO MODE IS RTTY
INPEND:	CALL	IOTERM	;OVERLAY TERMINAL I/O
	SENSE		;GET CODE INPUT LINE
	JZ	INPEND	;NOTHING PENDING, WAIT
	LXI	H,INCHAR	;POINT AT HOLDING REG
	MVI	M,1	;SET UP TO SHIFT IN MORSE
INTIME:	LXI	H,TIMER	;POINT AT TIMER REG
	MVI	M,1	;INITIALIZE FOR TIME=0
INSENS:	CALL	TICKI	;WAIT FOR PART OF A BAUD (1/8)
	LXI	H,TIMER	;UPDATE TIMER
	INR	M	;+1
	SENSE		;KEY DOWN?
	JNZ	INSENS	;WAIT FOR KEY UP
	;IF HERE, KEY IS NOW UP
	MVI	E,0	;SET E=0 FOR DOT, FIX LATER IF DASH
	MOV	A,M	;TIMER TO A REG (8*# OF BAUD)
	CPI	14	;DASH-N%=DOT+N%
	JNC	INDASH	;IF DASH, SERVICE DASH
	;SEE IF CLOCK MUCH TOO SLOW FOR DOT
	CPI	5	;SHOULD BE A 10 IDEAL
	JNC	INPOK	;CLOCK IS GOOD ENOUGH
	CALL	ABAUD	;HL=A*BAUDI/10
	ADD	L	;NEW BAUDI TO A AND FLAGS
	JNZ	OKBAUD	;ZERO IS A NO-NO!
	INR	A	;A =1 FOR NON-ZERO
OKBAUD:	STA	BAUDI	;THENCE TO MEMORY
	JMP	INPOK


	;IF HERE, SYMBOL IS DASH, UPDATE BAUDI FOR TRACKING
INDASH:	CPI	35	;CLOCK TOO FAST?
	JC	OKDASH	;NO.
	MVI	B,0	;A=A/3 WHEN DONE HERE
DIV3:	INR	B	;ALWAYS GOES ONCE
	SUI	3	;TAKE IT OUT
	JNC	DIV3	;LOOP UNTIL DONE
	MOV	A,B	;A NOW A/3
	CALL	ABAUD	;HL=(A/3)*BAUDI/10
	MOV	A,L	;BAUDI TO A AND
	STA	BAUDI	;TO MEMORY
OKDASH:	MVI	E,1	;SET E=1 FOR DASH
INPOK:	LXI	H,INCHAR	;POINT AT CHAR HOLDING REG
	MOV	A,M	;GET PARTIAL CHAR TO A REG
	RAL		;SHIFT UP ONE BIT
	ANI	376	;JUNK THE OLD CARRY BIT
	ORA	E	;BRING IN NEW SYMBOL FROM E REG
	MOV	M,A	;NEW PARTIAL CHAR TO INCHAR

	;TIME THE INTERSPACE TO FIND WHAT TYPE IT IS.
	LXI	H,TIMER	;RESET THE TIMER
	MVI	M,1	;TIMER RESET
UPTIME:	CALL	TICKI	;DELAY 1/8 OF A BAUD TIME
	SENSE		;GET THE KEY STATUS
	JNZ	INTIME	;KEY DOWN, GET NEXT SYMBOL
	LXI	H,TIMER	;UPDATE THE TIME
	INR	M	;+1
	MOV	A,M	;GET TIMER TO A FOR COMPARE
	CPI	377	;END OF MESSAGE?
	JNZ	NOTEOM	;KEEP LOOPING,
	MVI	B,<12>	;END OF MESSAGE, CR-LF-CR-LF
	CALL	PPAK
	CALL	PPAK
	JMP	INPEND	;TO TOP OF LOOP UNTIL MONITOR SAYS OTHERWISE
NOTEOM:	CPI	50	;END OF WORD? 70 IDEAL
	JNZ	ENDLET	;NO.
	MVI	A,1	;YES, OUTPUT A SPACE
	JMP	MPAK	;DO IT OUT RIGHT.
ENDLET:	CPI	15	;END OF LETTER? 30 IDEAL
	JNZ	UPTIME	;NO, KEEP TIMING THE UP TIME
	LXI	H,INCHAR	;POINT AT HOLDING REG
	MOV	A,M	;MORSE FROM HOLDING REG TO A REG
	MVI	M,1	;RESET THE HOLDING REG FOR NEXT CHAR
MPAK:	STC		;SET C FLAG FOR GUARD BIT
1$:	RAL
	JNC	1$	;IF NO LEFT GUARD, LOOP
	ORA	A	;IF ZERO, ERROR CHAR WAS SEEN.....
	JNZ	2$	;NOT ERR CHAR
	MVI	A,DELSYM	;SET UP FOR DELETE SYMBOL
	JMP	3$
2$:	LXI	D,MORTAB	;SET UP FOR MORSE CONVERSION
	LXI	B,MOREND
	CALL	XLATR2	;MORSE TO ASCII
3$:	MOV	B,A	;SET UP TO PRINT WITH PPAK
	CALL	PPAK	;PRINT THE CHARACTER
	JMP	UPTIME	;KEEP TIMING THE UP TIME
;RTTY SECTION FOR BAUDOT INPUT
INPRTY:	CALL	IOTERM		;OVERLAY WITH CONSOLE IO
	LDA	RUSART+1	;GET STATUS OF
	ANI	2		;DA BIT OF USART
	JZ	INPRTY		;WAIT FOR DA
	LXI	H,LETFIG	;POINT AT SHIFT MEMORY
	LDA	RUSART		;CHAR TO A
	CPI	LTRS		;SHIFT?
	JNZ	1$		;NO
	MVI	M,200		;YES, SET SHIFT MODE
	JMP	INPRTY
1$:	CPI	FIGS		;SHIFT?
	JNZ	2$		;NO
	MVI	M,0		;YES, SET SHIFT MODE
	JMP	INPRTY
2$:	ORA	M		;CHAR "OR" WITH SHIFT BIT
	LXI	D,RTYTAB	;SET UP TO CONVERT TO ASCII
	LXI	B,RTYEND
	CALL	XLATR2
	MOV	B,A		;SET UP TO PRINT
	CALL	PPAK
	JMP	INPRTY		;LOOP UNTIL MONITOR SAYS STOP


;SUBROUTINE TO GET BAUDI TO HL AND MULTIPLY BY A REG AND DIVIDE BY 10
ABAUD:	LXI	H,BAUDI
	MOV	L,M	;BAUDI TO L
	MVI	H,0	;ZAP H FOR DOUBLE PREC
	MOV	C,L	;COPY BC=HL
	MOV	B,H
	DCR	A	;ONCE ALREADY IN HL
MULT:	DAD	B	;ADD BC TO HL, A TIMES
	DCR	A
	JNZ	MULT	;FALL THROUGH AT A*HL
	CALL	DSHFTR	;/2
	CALL	DSHFTR	;/4
	CALL	DSHFTR	;/10
	RET



;SUBROUTINE TO DOUBLE PRECISION SHIFT THE HL RIGHT
DSHFTR:	PUSH	PSW	;DO NOT DESTROY A AND FLGS
	ORA	A	;CLEAR CY
	MOV	A,H	;HIGH BYTE
	RAR		;LSB TO CY
	MOV	H,A	;REST BACK TO H
	MOV	A,L	;LOW BYTE
	RAR		;MSB FROM H LSB, L LSB DUMPED
	MOV	L,A	;REST TO L
	POP	PSW
	RET

;SUBROUTINE USED TO OVERLAY I/O FOR COMPUTE BOUND ROUTINES
IOALL:	CALL	OTPUT	;CODE OUTPUT LINE
IOTERM:	CALL	KYBD	;TERMINAL INPUT
	CALL	PNTR	;TERMINAL OUTPUT
	RET


;ROUTINE TO ZERO THE LOG
CLRLOG:	LXI	H,LOGSAF	;MAKE SURE
	CALL	PRTMSG
CLRWYT:	CALL	UNPAK	;WAIT FOR ANSWER
	JZ	CLRWYT
	CPI	<15>	;CR TO CONTINUE
	JNZ	CLRLOG
	LXI	H,LOGSF2	;DOUBLE SURE
	CALL	PRTMSG
CLRWT2:	CALL	UNPAK	;WAIT FOR ANSWER
	JZ	CLRWT2
	CPI	<15>	;CR TO CONTINUE
	JNZ	CLRLOG
;ZERO OUT THE LOG
	LXI	H,LOGSTR	;LOG AREA START
	MVI	M,<15>	;CR TO HELP IN FILE LOOK UP
	INX	H
	SHLD	LOGPNT		;START IS NOW END
	MVI	M,0	;NULL BYTE TO END THE LOG
	JMP	CLRMD

	;SUBROUTINE TO TYPE AN ASCII STRING POINTED TO BY HL
;	ASCII STRING IS TERMINATED BY A ZERO (NULL) BYTE
PRTMSG:	XRA	A	;CLEAR A AND FLAGS
	ADD	M	;CHAR TO A AND FLAGS
	RZ		;NULL BYTE, ALL DONE
	MOV	B,A	;CHAR TO B REG FOR PPAK
	PUSH	H	;SAVE POINTER
	CALL	PPAK	;CHAR TO PRINT FIFO
	POP	H	;GET POINTER
	JZ	PRTOK	;IF NOT ERROR CONTINUE
	PUSH	H	;SAVE POINTER
	CALL	IOTERM	;DO SOME I/O TO EMPTY THE BUFFER
	POP	H	;GET THE POINTER
	JMP	PRTMSG	;TRY AGAIN
PRTOK:	INX	H	;NEXT CHAR
	JMP	PRTMSG	;LOOP



;SUBROUTINE TO CONVERT A REG TO TWO DECIMAL ASCII DIGITS AND RETURN
;WITH THEM IN REGS A&B (MSD IN B).  A MUST BE LESS THAN 100.
BINDEC:	MVI	B,-1	;PRESET HIGH DIGIT COUNT
MSDLOP:	INR	B	;BUMP TENS COUNT
	SUI	10.	;AND REMOVE 10.
	JNC	MSDLOP	;LOOP IF NUMBER LARGE ENOUGH
	ADI	10.	;FIX IF NUMBER NOT LARGE ENOUGH
	ORI	60	;MAKE REMAINDER ASCII
	PUSH	PSW	;THEN SAVE AWHILE
	MOV	A,B	;GET MSD TO MAKE
	ORI	60	;ASCII
	MOV	B,A	;RESTORE TO B
	POP	PSW	;LSD BACK
	RET

;SUBROUTINE TO PICK UP # OF CHARACTERS DEFINED BY THE B REG
;AND PUT THEM IN BLOCK OF MEMORY STARTING AT HL FROM BLOCK OF
;MEMORY STARTING AT DE.  HL RETURNS POINTING TO NEXT FREE SPACE.
;NULLS ARE BLANKED, REPLACED WITH <40>
BLKIO:	LDAX	D	;BYTE TO A
	ORA	A	;SET UP Z FLAG TO FIND NULLS
	JNZ	1$
	MVI	A,<40>
1$:	MOV	M,A	;TO BUFFER
	INX	H	;NEXT FREE SPACE
	INX	D	;NEXT SOURCE CHAR
	DCR	B	;ANYMORE BYTES?
	JNZ	BLKIO	;YES, LOOP
	RET



;SUBROUTINE TO CONVERT ASCII BA REG TO BINARY IN A REG
DECBIN:	ANI	17	;SAVE LSB DATA
	PUSH	PSW	;NEED A AWHILE
	MOV	A,B	;TO FIX
	ANI	17	;THE MSD
	MOV	B,A
	POP	PSW
	INR	B	;SET Z FLAG IF B=0
	DCR	B
	RZ		;DONE SINCE MSD=0
1$:	ADI	10.	;MULTIPLY BY MSD
	DCR	B	;DONE?
	JNZ	1$	;NO,
	RET		;YES

;SUBROUTINE TO PRINT THE # OF CHAR IN REG C FROM BLOCK AT HL
CHRPAK:	MOV	B,M	;GET CHAR
	PUSH	B	;SAVE COUNTERS
	PUSH	H
	CALL	PPAK	;TO FIFO
	JNZ	1$	;ERR
	POP	H	;NO ERR
	POP	B
	INX	H	;NEXT LOCATION
	DCR	C	;DONE?
	RZ		;YES
	JMP	CHRPAK	;NOT YET
1$:	CALL	IOALL	;CLEAR I/O ERR
	POP	H
	POP	B
	JMP	CHRPAK	;TRY AGAIN


;SUBROUTINE TO READ CLOCK AND SET UP REGS FOR TIME
RCLOCK:	LDA	40162	;GET HOUR FROM THE FOREGROUND
	CALL	BINDEC	;CONVERT TO ASCII IN B-A
	LXI	H,TIME	;POINT AT REGS
	MOV	M,B	;MSD
	INX	H
	MOV	M,A	;LSD HOUR
	LDA	40163	;GET MIN FROM THE FOREGROUND
	CALL	BINDEC	;TO ASCII
	INX	H
	MOV	M,B	;MSD OF MIN
	INX	H
	MOV	M,A	;LSD OF MIN
	RET


;ROUTINE TO SET THE CLOCK, FALLS THROUGH TO ROUTINE TO READ CLOCK
SCLOCK:	LXI	H,TIME
	MVI	B,4	;4 DIGITS
2$:	PUSH	H
	PUSH	B
1$:	CALL	UNPAK	;GET CHAR FOR TIME
	JZ	1$	;WAIT FOR DIGIT
	POP	B
	POP	H
	MOV	M,A	;SAVE CHAR
	INX	H	;NEXT POSITION
	DCR	B	;GOT THE 4 DIGITS?
	JNZ	2$	;NOT YET
	LXI	H,TIME	;YES GET THE HOUR
	MOV	B,M	;MSD
	INX	H
	MOV	A,M	;LSD
	CALL	DECBIN	;CONVERT
	STA	40162	;SET CLOCK HOURS
	INX	H	;NOW DO MIN
	MOV	B,M	;MSD
	INX	H
	MOV	A,M	;LSD
	CALL	DECBIN	;CONVERT
	STA	40163	;SET CLOCK MINS

;ROUTINE TO PRINT THE CURRENT TIME
CLOCK:	CALL	RCLOCK	;SET TIME REG
	CALL	STIME	;PRINT TIME MSG
	JMP	CLRMD		;DONE




;CLEAR THE BUFFER AREA FOR CALL AND RST
LOG:	LXI	H,STATNE	;FIRST BUFFER START
	MVI	B,HSRST+3-STATNE	;# OF BYTES
10$:	MVI	M,<40>		;BLANK A BYTE
	INX	H
	DCR	B		;ONE LESS BYTE
	JNZ	10$

;PICK UP THE TIME OF QSO
	CALL	RCLOCK	;SET TIME

;PICK UP STATION CALL FROM "STATION"
	LXI	H,STACAL	;POINT AT BUFFER
	MOV	A,M		;ONLY 6 LETTERS IN CALL SIGNS
	CPI	7		;TOO MANY CHARS?
	JC	1$		;NO
	MVI	A,6		;YES
1$:	ORA	A	;ANY CHARS?
	JZ	8$	;NO.
	LXI	D,STATNE	;LOG BUFFER POINTER
	MOV	B,A		;CHAR COUNT TO B
	INX	H	;POINT AT DATA
2$:	MOV	A,M	;GET CHAR
	STAX	D	;TO DESTINATION
	INX	H	;NEXT SOURCE
	INX	D	;NEXT DESTINATION
	DCR	B	;ONE LESS CHAR
	JNZ	2$	;UNLESS DONE


;PICK UP PROBABLE RS/RST FROM MSG BUFFER C
8$:	LXI	H,MSGCBF+1	;POINT AT DATA IN BUFFER
	LXI	D,HSRST		;STORE HERE
	MVI	B,3		;ONLY 3 CHARS
	MOV	A,M	;ALLOW A LEADING BLANK IN THE BUFFER
	CPI	<40>
	JNZ	5$	;NOT A BLANK, GO PROCESS
	INX	H	;BLANK, DUMP IT
3$:	MOV	A,M	;GET CHAR
	CPI	<40>	;BLANK?
	JZ	4$
5$:	STAX	D	;SAVE IN RS/RST
	INX	H
	INX	D
	DCR	B	;DONE?
	JNZ	3$	;GET EITHER 3 CHARS OR A BLANK

;USE HIS RS/RST AS ESTIMATE OF MY RS/RST
4$:	MVI	B,3	;PICK UP 3 CHARS
	LXI	D,HSRST	;FROM HERE
	LXI	H,MYRST	;AND PUT HERE
	CALL	BLKIO

;LEAVE OLD ZONE AS ESTIMATE OF NEW ZONE

;PRINT OUT PROBABLE LOG ENTRY
PROLOG:	CALL	STIME	;TIME OF QSO
	CALL	SSTAT	;STATION WORKED
	CALL	SHRST	;HIS RS/RST
	CALL	SZONE	;HIS ZONE
	CALL	SMRST	;MY RS/RST

6$:	LXI	H,CORMSG	;CORRECT?
	CALL	PRTMSG
5$:	CALL	UNPAK	;CR IF CORRECT, N IF ERROR
	JZ	5$
	CPI	<15>	;DONE, GO LOG ENTRY
	JZ	ENTLOG
	CPI	'N	;ERROR, UPDATE LINES
	JZ	FIXLOG
	JMP	6$	;WRONG ANSWER

FIXLOG:	LXI	H,INSMSG	;TELL USER HOW TO FIX LOG
	CALL	PRTMSG

	CALL	SSTAT	;CALL SIGN CHECK
	LXI	H,STATNE
	MVI	B,6
	CALL	LOGFIX

	CALL	SHRST	;HIS RS/RST CHECK
	LXI	H,HSRST
	MVI	B,3
	CALL	LOGFIX

	CALL	SZONE	;CALL ZONE CHECK
	LXI	H,HSZNE
	MVI	B,2
	CALL	LOGFIX

	CALL	SMRST	;MY RS/RST CHECK
	LXI	H,MYRST
	MVI	B,3
	CALL	LOGFIX

	JMP	PROLOG	;RECHECK

;COMPLETE THE LOG ENTRY BY PUTTING IN ACTUAL LOG
ENTLOG:	LHLD	LOGPNT	;GET LOG LINE
	LXI	D,TIME	;LOG TIME
	MVI	B,4	;4 CHARS
	CALL	BLKIO
	MVI	M,<40>	;SPACE TO MAKE READABLE
	INX	H

	LXI	D,STATNE	;LOG STATION CALL
	MVI	B,6
	CALL	BLKIO
	MVI	M,<40>
	
	INX	H

	LXI	D,HSRST	;LOG HIS RST
	MVI	B,3
	CALL	BLKIO
	MVI	M,<40>
	INX	H

	LXI	D,HSZNE	;LOG HIS ZONE
	MVI	B,2
	CALL	BLKIO
	MVI	M,<40>
	INX	H

	LXI	D,MYRST	;LOG MY RST
	MVI	B,3
	CALL	BLKIO
	MVI	M,<15>	;END OF LOG ENTRY
	INX	H

	MVI	M,0	;NEW END OF LOG
	SHLD	LOGPNT	;NEXT LOG ENTRY WILL START HERE
	MVI	D,-<MEMEND-100/400>	;LOG BUFFER END FLAG
	MVI	E,-<MEMEND-100&377>
	DAD	D
	LXI	H,ENDERR	;POINT AT END WARNING MESSAGE
	CC	PRTMSG		;BUT PRINT MESSAGE ONLY IF ERROR
	JMP	CLRMD	;NEXT COMMAND


;COMMAND TO PRINT LOG
GETLOG:	CALL	PNTLOG
	JMP	CLRMD


;SUBROUTINE TO PRINT OUT THE LOG
PNTLOG:	LXI	H,LHDMSG	;LOG HEADER
	CALL	PRTMSG
	LHLD	LOGCMP		;START OF NON COMPRESSED LOG DATA
	CALL	PRTMSG
	RET



;SUBROUTINES FOR HANDLING MESSAGES FOR LOG I/O OPERATOR HELP

STIME:	LXI	H,TIMMSG	;TIME OF DAY FOR QSO
	CALL	PRTMSG
	MVI	C,4
	LXI	H,TIME
	CALL	CHRPAK
	RET

SSTAT:	LXI	H,STAMSG	;STATION WORKED
	CALL	PRTMSG
	MVI	C,6
	LXI	H,STATNE
	CALL	CHRPAK
	RET

SHRST:	LXI	H,HRSMSG	;HIS RS/RST
	CALL	PRTMSG
	MVI	C,3
	LXI	H,HSRST
	CALL	CHRPAK
	RET

SZONE:	LXI	H,ZNEMSG	;HIS ZONE
	CALL	PRTMSG
	MVI	C,2
	LXI	H,HSZNE
	CALL	CHRPAK
	RET

SMRST:	LXI	H,MRSMSG	;MY RS/RST
	CALL	PRTMSG
	MVI	C,3
	LXI	H,MYRST
	CALL	CHRPAK
	RET


;SUBROUTINE TO PATCH A LOG FIELD IF NEEDED, ENTERED
;WITH FIELD SIZE IN B, ADDRESS IN HL.  RETURNS ON CR OR FULL FIELD.
LOGFIX:	MOV	C,B	;SAVE SIZE IN CASE OF RUBOUT
	PUSH	B
	PUSH	H
1$:	CALL	UNPAK	;CR OR NEW DATA
	JZ	1$
	POP	H
	POP	B
	CPI	<15>	;CR?
	RZ		;NO CHANGE EXIT
	PUSH	PSW	;SAVE CHAR
	PUSH	B
	PUSH	H
	MVI	D,<40>
2$:	MOV	M,D	;BLANK A BYTE
	INX	H	;NEXT
	DCR	B	;UNLESS DONE
	JNZ	2$
	POP	H
	POP	B
	POP	PSW	;GET THE CHAR BACK
;SERVICE RUBOUTS HERE
4$:	CPI	DELETE	;RUBOUT?
	JNZ	5$	;NO,
	MOV	A,C	;YES, BUT LEGAL?
	CMP	B	;LEGAL IF NOT EMPTY FIELD
	JZ	6$	;NOT LEGAL
	DCX	H	;REMOVE THE LAST CHAR FROM FIELD
	INR	B
	JMP	6$
5$:	MOV	M,A	;CHAR TO FIELD
	INX	H	;NEXT LOCATION
	DCR	B	;FIELD FULL
	RZ		;YES, EXIT
6$:	PUSH	B	;NO
	PUSH	H
3$:	CALL UNPAK	;GET NEXT CHAR
	JZ	3$
	POP	H
	POP	B
	CPI	<15>	;CR?
	RZ		;IF YES, DONE
	JMP	4$



;THIS SECTION DOES A LOG LOOK UP TO LOCATE A QSO
FIND:	LXI	H,LOGSTR	;POINT AT LOG
	LXI	D,STACAL	;POINT AT CALL SIGN
	LDAX	D		;PICK UP CHAR COUNT
	ORA	A		;SET FLGS
	MOV	C,A	;SAVE CALL CHAR COUNT IN C REG
	JNZ	2$
1$:	LXI	H,ERRMSG	;NOTHING TO FIND EXIT
	CALL	PRTMSG
	JMP	CLRMD		;EXIT
2$:	XRA	A
	ADD	M	;ANYTHING IN LOG?
	JZ	1$	;NO
5$:	LXI	D,STACAL+1	;POINT AT DATA IN CALL
	MVI	B,0		;ZERO CHAR COUNTER
4$:	XRA	A
	CMP	M		;NULL BYTE IN LOG?
	JZ	NOTFND		;YES, END OF LOG
	MVI	A,<40>		;DELIMITING BLANK?
	CMP	M
	INX	H		;BUMP POINT NOW, FOR LATER
	JNZ	4$		;FIND THE DELIMITER FIRST
	LDAX	D		;LOG AND CALL EQUAL?
	CMP	M
	JZ	3$		;YES
	INX	H		;NO, TRY NEXT CHAR
	JMP	4$
3$:	INR	B		;ONE LESS CHAR
	MOV	A,B	;ALL CHAR IN CALL DONE?
	CMP	C
	JNZ	6$		;NOT YET
	INX	H	;IF DONE, THIS CHAR IS A BLANK
	MVI	A,<40>
	CMP	M
	JZ	FOUND	;BLANK, DONE
6$:	INX	H		;NO, KEEP TRYING
	INX	D
	MOV	A,M		;GET LOG CHAR
	ORA	A		;NULL BYTE?
	JZ	NOTFND
	LDAX	D		;CALL CHAR TO A
	CMP	M		;LOG EQUAL CALL?
	JZ	3$		;YES, NEXT CHAR
	JMP	5$		;NO, RESET CALL AND KEEP LOOKING




;TELL USER THE RESULT OF THE SEARCH
FOUND:	INR	A	;CLEAR THE Z FLG
NOTFND:	PUSH	PSW	;SAVE FLG
;ENLIGHTEN THE USER
	LXI	H,FMSG	;STATION "
	CALL	PRTMSG
	LXI	H,STACAL	;CALL
	MOV	C,M		;# OF CHAR
	INX	H		;PICK UP DATA
	CALL	CHRPAK		;PRINT THE CALL SIGN
	POP	PSW		;FOUND OR NOT FOUND?
	JNZ	FND		;FINISH FOUND
	LXI	H,NFMSG		;NOT FOUND IN LOG
	CALL	PRTMSG
	JMP	CLRMD		;EXIT
FND:	LXI	H,FNDMSG	;FOUND MESSAGE
	CALL	PRTMSG
	JMP	CLRMD


;COMMAND ROUTINE TO PRINT AND THEN COMPRESS THE LOG TO THE FORM
;CALL<40>CALL<40>CALL......CALL<40><0>
COMPRS:	CALL	PNTLOG	;UPDATE THE LOG PRINTOUT
	LHLD	LOGCMP	;POINT AT NOT YET COMPRESSED LOG
	MOV	D,H	;POINT DE AT START OF COMPRESSED OUTPUT
	MOV	E,L
	INX	H	;SKIP INITIAL CR <15>
3$:	LXI	B,5	;SET BC=5 FOR DAD
	MOV	A,M	;GET LOG CHAR TO TEST FOR END LOG
	CPI	<0>	;END?
	JZ	4$	;YES, EXIT
	DAD	B	;NO, SKIP HHMM<40>
1$:	MOV	A,M	;GET CALL LETTERS
	STAX	D	;AND SAVE INCLUDING <40> DELIMITER
	CPI	<40>	;END OF CALL SIGN YET?
	INX	D	;NEXT PAIR
	INX	H
	JZ	2$	;END OF CALL SIGN, EXIT
	JMP	1$
2$:	MOV	A,M	;FIND END OF LINE
	CPI	<15>
	INX	H	;SET UP FOR NEXT CHAR
	JNZ	2$	;END OF LINE NOT FOUND YET
	JMP	3$	;END OF LINE NOW FOUND
4$:	MOV	H,D	;CLOSE AND RESET LOG
	MOV	L,E	
	MVI	M,<15>	;CR TO START NON-COMPRESSED LOG
	SHLD	LOGCMP	;NEW NON-COMPRESSED LOG START
	INX	H
	MVI	M,<0>	;NULL TO CLOSE LOG
	SHLD	LOGPNT	;NEW FREE SPACE POINTER
	JMP	CLRMD


;MESSAGES TO BE USED BY THE PRTMSG SUBROUTINE
LHDMSG:	.ASCII	<15>/    STATION WORKED MY/<15>
	.ASCII	/TIME  CALL  RST ZN RST/<15>
	.ASCIZ	/----------------------/
FMSG:	.ASCIZ	<15>/STATION /
NFMSG:	.ASCII	/ NOT/
FNDMSG:	.ASCIZ	/ FOUND IN LOG./<15>
STAMSG:	.ASCIZ	<15>/STATION WORKED: /
HRSMSG:	.ASCIZ	<15>%HIS RS/RST: %
ZNEMSG:	.ASCIZ	<15>/ZONE OF STATION WORKED: /
MRSMSG:	.ASCIZ	<15>%MY RS/RST IS: %
CORMSG:	.ASCIZ	<15>/IS THE ABOVE CORRECT? (TYPE N IF NO, CR TO LOG) /
INSMSG:	.ASCII	<15>/IF DATA IS CORRECT "CR", ELSE TYPE  /
	.ASCIZ	/CORRECT DATA UNTIL "CR" OR FIELD IS FULL./
LOGSF2:	.ASCII	<15>/REALLY??/
LOGSAF:	.ASCIZ	<15>/ZAP THE LOG? (CR TO CONTINUE, ^C TO ABORT)/
TIMMSG:	.ASCIZ	<15>/TIME IS /
ERRMSG:	.ASCIZ	<15>/BUFFER IS EMPTY!!!!/<15>
ENDERR:	.ASCIZ	<15>/!!! WARNING !!! LOG AREA IS ALMOST FULL !!!/


;***ANYTHING BEFORE THIS POINT CAN BE IN PROM***


;***EVERYTHING AFTER THIS POINT MUST BE IN RAM***

	.=40400	;USE NEXT RAM BLOCK ABOVE MDP BLOCK

LETFIG:	.BYTE	0	;RTTY SHIFT MEMORY:=200 FOR LTRS, =0 FOR FIGS
RTTYMD:	.BYTE	0	;=0 IF IN RTTY MODE, ELSE MORSE CODE MODE
CMMND:	.BYTE	0	;0=NORMAL MODE, OTHERWISE COMMAND MODE
TWIDTH:	.BYTE	0	;WHEN BYTE IS ZERO, GENERATE A CR/LF
TFILL:	.BYTE	0	;COUNTER FOR FILL CHARACTERS
SOH:	.BYTE	0	;SUBMODE FOR DMPSUB   0=PRINT   1=SEND
BAUD:	.BYTE	0	;WPM CONSTANT (SEE HEADING ON PROGRAM)
BAUDI:	.BYTE	0	;INPUT WPM VALUE (GETS MODIFIED)
TIMER:	.BYTE	0	;TIME BAUD *8 (10 OCTAL) COUNTER
RANCHR:	.BYTE	5	;RANDOM COUNTER REGISTER FOR QUIZ AND RQUIZ
	.BYTE	161	;SAVE LOCATION FOR ADDITIVE ELEMENT FOR
			;THE RANDOM # GENERATOR. MUST IMMEDIATELY FOLLOW RANCHR
QTEMP:	.BYTE	0	;TEMP MEMORY FOR QUIZ AND RQUIZ CHARACTER OUTPUT
GRPCNT:	.BYTE	0	;COUNTER FOR RQUIZ CHAR GROUP
CHRCNT:	.BYTE	0	;COUNTER FOR RQUIZ CHAR/GROUP
INCHAR:	.BYTE	0	;INPUT CHAR HOLDING REG


KYFIFO:	.=.+BUFSKY	;INPUT BUFFER
PNFIFO:	.=.+BUFSPN	;PRINTER BUFFER
OTFIFO:	.=.+BUFOUT	;OUTPUT BUFFER FOR CODE
MSGABF:	.=.+MSGSZ	;MESSAGE BUFFER A
MSGBBF:	.=.+MSGSZ	;MESSAGE BUFFER B
MSGCBF:	.=.+MSGSZ	;MESSAGE BUFFER C
STACAL:	.=.+7		;STATION BEING CALLED, 6 CHAR AND COUNTER
TIME:	.=.+4		;ASCII TIME STRING
STATNE:	.=.+6		;STATION CALL FOR LOG
HSRST:	.=.+3	;STATION WORKED RST
HSZNE:	.=.+2	;STATION WORKED ZONE
MYRST:	.=.+3	;MY RST

	.=.+200	;200 OCTAL BYTES FOR THE STACK
STACK:	.BYTE	0	;FOR THE 8080 CPU

LOGPNT:	.=.+2	;FREE SPACE POINTER FOR LOG
LOGCMP:	.=.+2	;START OF NON COMPRESSED LOG
LOGSTR:		;REST OF MEMORY IS AVAILABLE FOR LOG STORAGE
	.END	100400	;100400 KEEPS DATA I/O PROM BURNER HAPPY
                                                                                                                                                                                                                                  