	.PREL
	.IDENT	BITBANG
	.INSERT	BBEQU.ASM
	.DEFINE	WASTE[TIME,%LAB]=[
	MVI	A,TIME
%LAB:	DCR	A
	JRNZ	%LAB]
BANGER=99H	; BIT BANGER IO PORT
; *****
; *
; * COMMAND TO READ BLOCK INTO MEMORY
; * GET variable
; *
; *****
GETC::	CALL	TSTVFF#
	CALL	TAPGET
	RST	RSTFIN
; *****
; *
; * LOAD PROGRAM INTO MEMORY
; *
; *****
LOADC::
	LXI	H,TEXT#	; HL=TEXT AREA START ADDR
	CALL	TAPGET
	SHLD	TXTUNF#	; SET NEW TXTUNF
	JMP	CLRSCR#	; ENTER CLEAR TO END
; *****
; *
; * READ BLOCK INTO MEMORY
; * HL=READ ADDRESS
; *
; *****
TAPGET:
	PUSH	D
	DI
..SENW:
	CALL	INCHAR		; AWAIT SENTINEL CHARACTER
	MOV	A,C
	JRZ	..SENW
	CPI	0A5H
	JRNZ	..SENW
	LXI	D,4000H		; DE=FEEDBACK STORE ADDR
..CHRL:
	PUSH	D
	CALL	INCHAR
	POP	D
	JRZ	..DONE
	MOV	M,C
	MOV	A,C
	STAX	D		; GIVE FEEDBACK ON SCREEN
	INX	D		; BUMP FEEDBACK ADDR
	RES	4,D		; CONSTRAIN TO 4000H-4FFFH
	INX	H
	JMPR	..CHRL
..DONE:
	EI
	POP	D
	RET
; *****
; *
; * SUBROUTINE TO INPUT A CHARACTER
; * RETURNS CHARACTER IN C
; * AND STATUS OF NONZERO UNLESS A TIMEOUT HAPPENED
; * IN WHICH CASE ZERO STATUS IS RETURNED
; *
; *****
INCHAR:
	LXI	B,810H	; B=BIT CTR, C=TIMEOUT FACTOR
..SBW:	CALL	INBIT	; AWAIT START BIT
	JRZ	..GETL
	DCR	C	; NOT YET - DCR TIMEOUT
	JRNZ	..SBW	; IF COUNTED DOWN
	RET		; RETURN ZERO SET
..GETL:	CALL	INBIT
	RRC		; BIT GOT TO CY
	RARR	C	; SHIFT INTO C HO
	DJNZ	..GETL
; NOW FALL INTO INBIT TO EAT THE STOP BIT
INBIT:
	IN	BANGER	; WAIT TILL WE GET A TRANSITION
	MOV	E,A
..INBW:	IN	15H	; CHECK FOR ABORT
	ANA	A
	JNZ	INIT0#	; HALT SET?
	IN	BANGER
	XRA	E
	RRC
	JRNC	..INBW
	WASTE	30	; WAIT UNTIL SAMPLE POINT
	IN	BANGER
	XRA	E	; COMPARE TO OLDER STUFF
	ANI	1
	RZ		; 0 IF TRANSITION HAPPENED
	WASTE	29	; ELSE WAIT UNTIL MIDDLE OF NEXT CYCLE
	INR	A	; RETURN VAL OF 1
	RET
; *****
; *
; * COMMAND TO WRITE OUT THE PROGRAM
; *
; *****
SAVEC::
	PUSH	D
	LHLD	TXTUNF#
	LXI	D,TEXT#	; DE=START
	ANA	A
	DSBC	D
	XCHG		; HL=ADDR,DE=SIZE
	JMPR	SAVEE
; *****
; *
; * COMMAND TO WRITE OUT A BLOCK OF WORDS ON TAPE
; * PUT variable,#words
; *
; *****
PUTC::
	CALL	TSTVFF#	; GRAB A VARIABLE
	PUSH	H
	TSTCC	COMMA,BADSAV
	RST	RSTEXP	; GET NUMBA OF BYTES
	MOV	A,H	; REJECT BIZARRE VALUES
	ORA	L	; LIKE ZERO
	JZ	QHOW#
	BIT	7,H	; OR NEGATIVE VALUES
	JNZ	QHOW#
	DAD	H	; CONVERT WORDS TO BYTES
	XCHG		; COUNT=DE
	XTHL		; STK=SCAN, HL=START
SAVEE:
	DI
	CALL	LEADER	; WRITE OUT LEADER
	MVI	C,0A5H	; WRITE SENTINEL
	CALL	OUTBYT
	CALL	WRBLOC	; AND DATA BLOCK
	CALL	LEADER	; THEN TRAILER
	EI
	POP	D
	RST	RSTFIN
BADSAV:	JMP	QWHAT#
; *****
; *
; * SUBROUTINE TO WRITE OUT BLOCK OF BYTES
; * HL=LIST, DE=# OF BYTES
; *
; *****
WRBLOC:
..BYTL:
	MOV	C,M
	CALL	OUTBYT
	INX	H
	DCX	D
	MOV	A,D
	ORA	E
	JRNZ	..BYTL
	RET
; *****
; *
; * WRITE OUT A BYTE ONTO TAPE
; *
; * THIS ROUTINE IS TIME SENSITIVE! CHANGE CAREFULLY!
; *
; *****
OUTBYT:
	CALL	WRZERO		; WRITE START BIT
	WASTE	19		; FINISH START BIT
	MVI	B,8		; WRITE OUT 8 BITS
..WRL:	RRCR	C	; SHIFT NEXT BIT TO CY
	JRC	..WR1	; BRANCH ON BIT VALUE
	CALL	WRZERO	; THIS GUY ZERO
	WASTE	19
	JMPR	..WRE
..WR1:
; WRITE ONE BIT
	CALL	WRONE
	WASTE	42
..WRE:
	DJNZ	..WRL	; LOOP TILL BYTE DONE
	CALL	WRONE	; WRITE STOP BIT
	WASTE	43
	RET
; SUBROUTINE TO WRITE OUT 3 SECONDS WORTH OF LEADER
LEADER:
	LXI	B,3600
..LDR1:
	WASTE	43
	CALL	WRONE
	DCX	B
	MOV	A,B
	ORA	C
	JRNZ	..LDR1
	WASTE	42
	RET
; SUBROUTINE TO WRITE 1 HALF CYCLE OF A ONE BIT
; 1/1200 SEC
WRONE:
	OUT	BANGER
	WASTE	46
	OUT	BANGER
	RET
; SUBROUTINE TO WRITE 1 HALF CYCLE OF A ZERO BIT
; 1/2400 SEC
WRZERO:
	OUT	BANGER
	WASTE	23
	OUT	BANGER
	RET
	.END
                                      