;  SLAVE NETWORK INPUT OUTPUT SYSTEM FOR CP/NET-86
;
;  1983.9.4.	VER.1.00
;
BASE	EQU	100H			;FOR RELOCATION
;
;
	TITLE	'SLAVE NETWORK INPUT OUTPUT SYSTEM FOR CP/NET-86'
;
;  EQUATIONS OF SLAVE PROCESSOR ID CODE
;
SLVID	EQU	10H
;
;  EQUATIONS OF NETWORK STATUS BYTE
;
ACTIVE	EQU	10H			;SLAVE LOGGED IN ON NETWORK
RCVERR	EQU	2H			;ERROR IN RECEIVED MESSAGE
SNDERR	EQU	1H			;UNABLE TO SEND MESSAGE
;
;  EQUATIONS OF CODE & DATA
;
SOH	EQU	01H			;START OF HEADER
STX	EQU	02H			;START OF DATA
ETX	EQU	03H			;END OF DATA
EOT	EQU	04H			;END OF TRANSMISSION
ENQ	EQU	05H			;ENQUIRE
ACK	EQU	06H			;ACKNOWLEDGE
ACKS	EQU	07H			;SECOND ACKNOWLEDGE
LF	EQU	0AH			;LINE FEED
CR	EQU	0DH			;CARRIAGRE RETURN
NAK	EQU	15H			;NEGATIVE ACKNOWLEDGE
;
CBUFPR	EQU	9			;PRINT BUFFER BDOS FUNCTION
LOGIN	EQU	64			;LOGIN NDOS FUNCTION NUMBER
;
TMORTY	EQU	100			;TIME OUT RETRY COUNT
MAXRTY	EQU	10			;SEND MESSAGE RETRY COUNT
;
;  EQUATIONS OF INPUT OUTPUT PORT & ADDRESS
;
BDOS	EQU	224			;BDOS INTTERUPT
;
COMPRT	EQU	0D0H			;COMMUNICATION PORT
STATI	EQU	COMPRT			;INPUT STATUS
DPRTI	EQU	COMPRT+2		;DATA PORT
MSKI	EQU	01H			;INPUT READY BIT
;
STATO	EQU	COMPRT			;OUTPUT STATUS
DPRTO	EQU	COMPRT+2		;DATA PORT
MSKO	EQU	80H			;OUTPUT READY BIT
;
;
	CSEG
	ORG	BASE
;
;  JUMP VECTOR FOR SNIOS ENTRY POINTS
;
	JMP	NTWKIN			;NETWORK INITIALIZE
	JMP	NTWKST			;NETWORK STATUS
	JMP	CNTBAD			;RETURN CONFIGRATION TABLE ADDRESS
	JMP	SNDMSG			;SEND MESSAGE
	JMP	RCVMSG			;RECEIVE MESSAGE
	JMP	NTRSET			;NETWORK ERROR RESET
	JMP	NTWKWB			;NETWORK WARM BOOT
	JMP	NTWKEN			;RETURN END ADDRESS
;
;
PTABLE	EQU	$
	DSEG
	ORG	OFFSET PTABLE
;
;  SLAVE CONFIGRATION TABLE
;
CNFTBL	DB	0			;NETWORK STATUS BYTE
	DB	SLVID			;SLAVE PROCESSOR ID
	DB	0,0			;A: DISK DEVICE
	DB	0,0			;B: DISK DEVICE
	DB	0,0			;C: DISK DEVICE
	DB	0,0			;D: DISK DEVICE
	DB	80H,0			;E:		A: OF MASTER 0
	DB	81H,0			;F:		B: OF MASTER 0
	DB	82H,0			;G:		C: OF MASTER 0
	DB	83H,0			;H:		D: OF MASTER 0
	DB	84H,0			;I:		E: OF MASTER 0
	DB	85H,0			;J: 		F: OF MASTER 0
	DB	0,0			;K: DISK DEVICE
	DB	0,0			;L: DISK DEVICE
	DB	0,0			;M: DISK DEVICE
	DB	0,0			;N: DISK DEVICE
	DB	0,0			;O: DISK DEVICE
	DB	0,0			;P: DISK DEVICE
;
	DB	0,0			;CONSOLE DEVICE
;
	DB	0,0			;LIST DEVICE
	DB	0			;BUFFER INDEX
;
CNFTBS	DB	0			;FMT  MESSAGE BUFFER FOR LISTER
	DB	0			;DID
	DB	0			;SID
	DB	5			;FNC  LIST OUT
	DB	0			;SIZ
	RS	1			;MESSAGE 0  LISTER NUMBER
	RS	35			;MESSAGE 1 - 128  OUTPUT DATA
;
;  COMMENT  DESTROYED BY LIST OUT TO NETWORK
;
CSTUP	DB	'SNIOS OF CP/NET-86 XYZ  VER.1.00  SLAVE ID = '
CSTIDN	DB	'00',CR,LF,'$'
;
;
MAINP	EQU	$
	CSEG
	ORG	OFFSET MAINP
;
;  SET SLAVE ID NUMBER
;
SETIDN:
	MOV	BX,OFFSET CSTIDN
	MOV	AL,CNFTBL+1		;GET SLAVE ID
	MOV	CL,AL
	ROR	AL,1
	ROR	AL,1
	ROR	AL,1
	ROR	AL,1
	CALL	SETIDS			;SET UPER NIBBLE
	MOV	AL,CL
SETIDS:
	AND	AL,0FH
	ADD	AL,'0'
	CMP	AL,'0'+10
	JC	$+4			;0 TO 9
	ADD	AL,7			;A TO F
	MOV	[BX],AL
	INC	BX
	RET
;
;  INITIAL COMMENT OUT ROUTINE
;
INITCM:
	CALL	SETIDN			;SET ID NUMBER
	MOV	DX,OFFSET CSTUP
	MOV	CL,CBUFPR
	INT	BDOS			;OUT COMMENT
	XOR	AL,AL
	MOV	FINIT,AL
	RET				;ZERO IS SUCCESS END
;
;  INITIALIZE NETWROK
;  OUTPUT
;  AL:0 OK
;
NTWKIN:
	MOV	AL,CNFTBL+1		;GET SLAVE PROCESSOR ID
	MOV	CNFTBS+2,AL		;SAVE SID FOR LISTER
	CALL	NTRSET			;RESET COMMUNICATION INTERFACE
	MOV	AL,FINIT
	OR	AL,AL
	JNZ	INITCM			;OUT INITIAL COMMENT
	RET				;INITIALIZED
;
;  OUTPUT STATUS OF NETWORK
;  OUTPUT
;  AL:STATUS
;
NTWKST:
	MOV	AL,CNFTBL		;GET NETWORK STATUS
	MOV	AH,AL
	AND	AH,NOT (RCVERR+SNDERR)
	MOV	CNFTBL,AH		;OFF ERROR BITS
	RET
;
;  RETURN CONFIGRATION TABLE ADDRESS
;  OUTPUT
;  BX:CONFIGRATION TABLE POINT
;
CNTBAD:
	MOV	BX,OFFSET CNFTBL
	RET
;
;  SEND MESSAGE ON NETWORK
;  INPUT
;  CX:MESSAGE ADDRESS  DS:SEGMENT
;
SNDMSG:
	MOV	AX,DS
	MOV	BP,CS
	MOV	DS,BP			;SET DSEG TO NORMAL
	MOV	MSGSEG,AX		;SAVCE SEGMENT
	MOV	MSGADR,CX		;SAVE MESSAGE ADDRESS
SNDMSR:					;RETRY LOOP
	MOV	AL,MAXRTY
	MOV	RTYCNT,AL		;INITIALIE RETRY COUNT
SEND:
	CALL	NTRSET			;RESET BUFFER
SENDS:
	MOV	ES,MSGSEG
	MOV	DI,MSGADR		;GET MESSAGE TOP
	MOV	DH,TMORTY		;TIME OUT RETRY COUNT
SENDWT:					;ENQUIRE RESPONSE WAIT LOOP
	MOV	DL,ENQ
	CALL	CHROUT			;SEND ENQUIRE TO MASTER
	CALL	CHARIN			;WAIT RESPONSE
	JNC	SENDGT			;GET RESPONSE
	DEC	DH			;TIME OVER
	JNZ	SENDWT			;SEND ENQUIRE ONCE MORE
	JMP	CHINTO			;TIME OVER FOR LINK
;
SENDGT:					;GET RESPONSE
	CMP	AL,ENQ			;CHECK SEND - SEND MODE
	JZ	SNDRCV			;CRASH SEND SO TO PASS RECEIVE MODE
	CALL	GETAK0			;GET RESPONSE OF ENQ
	MOV	DL,SOH
	MOV	CX,5			;HEADER LENGTH COUNT
	CALL	MSGOUT			;SEND SOH,FMT,DID,SID,FNC,SIZ
	XOR	AL,AL
	SUB	AL,DH
	MOV	DL,AL
	CALL	NETOUT			;SEND HCS (HEADER CHECK SUM)
	CALL	CHARIW			;GET RESPONSE
	JC	SENDOV			;TIME OVER
	CMP	AL,ACK
	JNZ	SENDGA			;NORMAL MODE
	CALL	CHARIW			;MAYBE BUFFER LEFT ACK, SO IGNORE
	JC	SENDOV			;TIME OVER
SENDGA:
	SUB	AL,ACKS
	JNZ	SENDOV			;MISS MATCH OF RESPONSE
	DEC	DI
	MOV	CL,ES:[DI]		;GET LENGTH
	INC	DI
	MOV	CH,0
	INC	CX
	MOV	DL,STX
	CALL	MSGOUT			;SEND STX,DB0,DB1,....
	MOV	DL,ETX
	CALL	NETOUT			;SEND ETX
	XOR	AL,AL
	SUB	AL,DH
	MOV	DL,AL
	CALL	NETOUT			;SEND DATA CHECK SUM
	MOV	DL,EOT
	CALL	CHROUT			;SEND END OF TRNASMISSION
	CALL	GETAKS			;** NEED CALL ******* FOR ERROR RETRY
	RET
;
SENDOV:					;TIME OVER OR SO
	JMP	GETATS
;
;  PASS RECEIVE FOR SEND & SEND MODE
;
SNDRCV:
	CALL	NTRSET			;CLEAR CURRENT BUFFER
	MOV	DH,TMORTY
SNDRCW:					;WAIT FOR ANOTHER ENQ
	CALL	CHARIN
	JNB	SNDRCG			;GET DATA
	DEC	DH			;TIME OVER
	JNZ	SNDRCW			;WAIT
SNDRCS:
	JMP	SEND			;MAYBE MISS LINK, SO TO SEND
;
SNDRCG:					;GET DATA
	CMP	AL,ENQ
	JNZ	SNDRCS			;MAYBE MISS LINK
	CALL	SNDACK			;SEND ACKNOWLEDGE
	CALL	CHARIW
	JC	SNDRCV			;NO RESPONSE, SO RETRY
	CMP	AL,SOH
	JNZ	SNDRCV
	MOV	DI,OFFSET DHEADR	;DUMMY HEADER BUFFER
	MOV	DH,AL
	MOV	AX,DS
	MOV	ES,AX
	MOV	CX,5
	CALL	MSGIN			;GET HEADER
	JC	SNDRCV			;TIME OUT
	CALL	NETIN			;GET CHECK SUM
	JC	SNDRCV			;TIME OUT RETRY
	JNZ	SNDRCN			;CHECK SUM ERROR
	CALL	SNDAKS			;SEND RESPONSE
	CALL	CHARIW
	JC	SNDRCV			;TIME OVER
	CMP	AL,STX			;CHECK START OF TEXT
	JNZ	SNDRCV			;MISS RETRY
	MOV	DH,AL			;INITIALIZE CHECK SUM
	MOV	CL,-1[DI]
	MOV	CH,0
	INC	CX
	INC	CX			;GET COUNT FOR READ
SNDRCL:					;DATA PASS RECEIVE LOOP
	CALL	NETIN			;GET ONE DATA
	JC	SNDRCV			;TIME OUT RETRY
	LOOP	SNDRCL			;TO NEXT DATA
	CMP	AL,ETX
	JNZ	SNDRCV			;MISS MATCH OF END CODE
	CALL	NETIN			;GET CHECK SUM
	JC	SNDRCV			;CHECK SUM ERROR
	CALL	CHARIN
	JC	SNDRCV			;TIME OVER
	CMP	AL,EOT			;END OF TRANSMISSION
	JNZ	SNDRCV			;END CODE ERROR
	OR	DH,DH
	JNZ	SNDRCN			;CHECK SUM ERROR
	CALL	SNDAKS
	JMP	SENDS			;RETURN TO SEND
;
SNDRCN:					;ERROR RESPONSE
	CALL	SNDNAK
	JMP	SNDRCV
;
;  GET ACKNOWLEDGE
;  OVERRIDING RETURN WHEN ERROR
;
GETAK0:				;CHECK ACKNOWLEDGE
	SUB	AL,ACK
	JNZ	SNDRTY
	RET			;OK END
;
CHINTO:				;CHARACTER IN TIME OUT
	MOV	AL,SNDERR
	CALL	ERETRN
	JMP	SNDMSR
;
GETAKS:					;GET SECOND ACKNOWLEDGE
	CALL	CHARIW
	JC	SNDRTY			;TIME OUT
	SUB	AL,ACKS
	JNZ	SNDRTY
	RET				;OK
;
SNDRTY:
	POP	BX			;DISCARD RETURN ADDRESS
GETATS:					;TIME OVER RETRY
	DEC	RTYCNT
	JZ	CHINTO
	JMP	SEND			;SEND AGAIN
;
;  RECEIVE MESSAGE FROM NETWORK
;  INPUT
;  CX:MESSAGE ADDRESS  DS:SEGMENT
;
RCVMSG:
	MOV	AX,DS
	MOV	BP,CS
	MOV	DS,BP
	MOV	MSGSEG,AX		;SAVE MESSAGE SEGMENT
	MOV	MSGADR,CX		;SAVE MESSAGE ADDRESS
RCVMSR:
	MOV	AL,MAXRTY
	MOV	RTYCNT,AL		;INITIALIZE RETRY COUNT
RECALL:
	CALL	RECEIV
	DEC	RTYCNT			;DOWN RETRY COUNT
	JNZ	RECALL			;RETRY
RCVTOT:					;TIME OUT
	MOV	AL,RCVERR
	CALL	ERETRN
	JMPS	RCVMSR
;
;  RECEIVE BODDY
;  RETURN OVERRIDING WHEN OK
;  SIMPLE RETURN IS ERROR
;
RECEIV:
	MOV	ES,MSGSEG
	MOV	DI,MSGADR		;GET MESSAGE ADDRESS
	MOV	DH,TMORTY		;TIME OUT RETRY
	CALL	NTRSET			;RESET INPUT BUFFER
RCVFST:					;RECEIVE FIRST CHARACTER LOOP
	CALL	CHARIN
	JNC	RCVGFS			;GET FIRST CHARACTER
	DEC	DH			;TIME OVER
	JNZ	RCVFST			;RETRY
	POP	BX
	JMPS	RCVTOT			;SET TIME OVER ERROR FLAG & RETRY
;
RCVGFS:					;GET FIRST CHARACTER
	CMP	AL,ENQ
	JNZ	RECEIV			;NOT ENQUIRE SO RETRY
	CALL	SNDACK			;RESPONSE TO MASTER
	CALL	CHARIW
	JC	RECEIE			;RETURN TO RECEIVE RETRY
	CMP	AL,SOH
	JNZ	RECEIE			;NOT START OF HEADER
	MOV	DH,AL			;START OF HEADER
	MOV	CX,5			;LENGTH OF HEADER
	CALL	MSGIN			;GET HEADER BLOCK
	JC	RECEIE			;TIME OVER
	CALL	NETIN			;GET HCS (HEADER CHECK SUM)
	JC	RECEIE			;TIME OVER RETRY
	JNZ	SNDNAK			;CHECK SUM ERROR
	CALL	SNDAKS			;SEND RESPONSE
	CALL	CHARIW			;WAIT DATA TOP
	JC	RECEIE			;TIME OVER
	CMP	AL,STX
	JNZ	RECEIE			;NOT START OF TEXT
	MOV	DH,AL			;START OF TEXT
	DEC	DI
	MOV	CL,ES:[DI]		;GET SIZE
	INC	DI
	MOV	CH,0
	INC	CX			;MAKE READ COUNT FOR DATA BLOCK
	CALL	MSGIN			;RECEIVE DATA
	JC	RECEIE			;TIME OVER
	CALL	CHARIN			;GET END CODE OF DATA BLOCK
	JC	RECEIE
	CMP	AL,ETX
	JNZ	RECEIE			;NOT END OF TEXT SO RETRY
	ADD	DH,AL
	CALL	NETIN			;GET CHECK SUM
	JC	RECEIE
	CALL	CHARIN			;GET LAST CODE
	JC	RECEIE
	CMP	AL,EOT
	JNZ	RECEIE			;NOT END OF TRANSMIT  SO ERROR
	OR	DH,DH
	JNZ	SNDNAK			;CHECK SUM ERROR
	POP	BX			;OK ALL PACKETTE IS RECEIVED
	MOV	DI,MSGADR
	INC	DI
	MOV	AL,CNFTBL+1		;GET SLAVE ID
	SUB	AL,ES:[DI]		;CHECK SID
	JZ	$+4
	MOV	AL,-1			;SID ERROR
	PUSH	AX
	CALL	SNDAKS			;SEND ACKNOWLEDGE
	POP	AX
RECEIE:
	RET
;
;  ROUTINES TO SEND RESPONSE CODES
;
SNDACK:				;SEND ACKNOWLEDGE
	MOV	DL,ACK
	JMPS	CHROUT
;
SNDAKS:				;SEND SECOND ACKNOWLEDGE
	MOV	DL,ACKS
	JMPS	CHROUT
;
SNDNAK:				;SEND NEGATIVE ACKNOWLEDGE
	MOV	DL,NAK
	JMPS	CHROUT
;
;  ERROR RETURN
;  INPUT
;  AL:ERROR BIT
;  OUTPUT
;  AL:-1
;
ERETRN:
	MOV	BX,OFFSET CNFTBL
	OR	[BX],AL			;ON ERROR BIT
	CALL	NTRSET			;RESET COMMUNICATION INTERFACE
	MOV	AL,-1			;ERROR RETUNR CODE
	RET
;
;  NETWORK ERROR RECOVER ROUTINE    RESET COMMUNICATION INTERFACE
;
NTRSET:
	MOV	AL,080H
	OUT	STATO,AL		;RESET
	RET
;
;  BOOTING UP ROUTINE
;
NTWKWB:
	JMPS	NTRSET			;RESET INTERFACE
;
;  RETURN END ADDRESS
;
NTWKEN:
	MOV	BX,OFFSET BOTTOM
	RET
;
;  NETWORK OUTPUT DATA
;  INPUT
;  DL:OUTPUT DATA
;  DH:CHECK SUM
;
NETOUT:
	ADD	DH,DL			;MAKE CHECK SUM
CHROUT:
	IN	AL,STATO
	AND	AL,MSKO			;GET OUTPUT READY MODE
	JNZ	CHROUT			;NOT READY
	MOV	AL,DL
	OUT	DPRTO,AL		;OUT DATA
	RET
;
;  INPUT FROM NETWORK
;  OUTPUT
;  AL:DATA
;  CF:ON TIME OVER   OFF GET DATA
;
CHARIW:					;LONG WAIT
	MOV	BH,0
	JMPS	CHARIM
;
CHARIN:
	STI
	MOV	BH,10			;10 MS = 192 CH / 192K BAUD
CHARIM:					;WAIT LOOP
	MOV	BL,125			;1 MS WAIT VALUE BY 5MHZ
CHARIL:					;1 MS WAIT LOOP
	IN	AL,STATI
	AND	AL,MSKI
	JZ	CHARIG			;READY
	DEC	BL
	JNZ	CHARIL			;WAIT OF 1 MS
	DEC	BH
	JNZ	CHARIM			;WAIT
	STC				;TIME OVER RETURN
	RET
;
CHARIG:
	IN	AL,DPRTI		;GET DATA
	RET
;
;  MESSAGE INPUT
;  INPUT
;  DI:DESTINATION ADDRESS  ES:SEGMENT
;  CX:INPUT COUNT
;
MSGIN:
	CLI
	CLD
MSGINL:
	IN	AL,STATI
	AND	AL,MSKI
	JZ	MSGINS			;READY
	CALL	CHARIN			;NOT READY SO WAIT
	JC	MSGINE			;TIME OUT
	CLI
	JMPS	MSGINS+2		;GET DATA
;
MSGINS:					;READY
	IN	AL,DPRTI		;GET DATA
	STOSB				;SAVE DATA
	ADD	DH,AL			;MAKE HASH
	LOOP	MSGINL			;TO NEXT BYTE
	OR	AL,AL			;OFF CF
MSGINE:
	STI
	RET
;
;  NETWORK INPUT
;  INPUT
;  DH:CHECK SUM
;  OUTPUT
;  AL:DATA
;  CF:ON TIME OVER
;  ZF:ON HASH TOTAL IS ZERO
;
NETIN:
	CALL	CHARIN			;RECEIVE BYTE IN BINARY MODE
	JC	NETINE
	ADD	DH,AL			;MAKE CHECK SUM
	OR	DH,DH			;OFF CARRY FLAG
NETINE:
	RET
;
;  MESSAGE OUT
;  INPUT
;  DI:SOURCE ADDRESS
;  CX:COUNT OF OUTPUT DATA
;  DL:PREAMBLE CODE
;
MSGOUT:
	MOV	DH,0			;CLEAR CHECK SUM
	CALL	NETOUT			;OUT PREAMBLE CODE
MSGOTL:					;OUT LOOP
	MOV	DL,ES:[DI]		;GET CODE
	INC	DI
	CALL	NETOUT			;OUT DATA
	LOOP	MSGOTL			;TO NEXT DATA
	RET
;
;
DTAREA	EQU	$
	DSEG
	ORG	OFFSET DTAREA
;
;  DATA AREA
;
FINIT	DB	-1			;INITIAL MODE -1 INITIAL
MSGADR	DW	0			;MESSAGE ADDRESS BUFFER
MSGSEG	DW	0			;MESSAGE SEGMENT
DHEADR	RB	5			;DUMMY HEADER BUFFER
RTYCNT	DB	0			;RETRY COUNT
;
;
BOTTOM:					;BOTTOM OF SNIOS
;
;
	END
