	title	'Master Network I/F Module'
	name	'netwrkif'
;	page	48
;***************************************************************
;***************************************************************
;**                                                           **
;**      M a s t e r   N e t w o r k   I / F   M o d u l e    **
;**                                                           **
;***************************************************************
;***************************************************************

;/*
;  Copyright (C) 1980
;  Digital Research
;  P.O. Box 579
;  Pacific Grove, CA 93950
;
;  Modified April 24, 1982
;
;*/

	
false	equ	0
true	equ	not false

z80	equ	false

	if	z80
	maclib	z80altos ; Altos 
	endif

debug	equ	false
modem	equ	false

mail	equ	true	; allocate storage and setup mailbox

WtchDg	equ	false	; include watch dog timer

mutexin	equ	false	; provide mutual exclusion on input
mutexout equ	false	; provide mutual exclusion on output

	NmbFcbs	equ	16	; Number of fcbs for each slave

	if	debug
NmbSlvs	equ	1

	lxi	sp,NtwrkIS0+2eh
	mvi	c,145
	mvi	e,64
	call	bdos	; set priority to 64
	lxi	h,UQCBNtwrkQI0
	lxi	d,UQCBNtwrkQO0
	lxi	b,BufferQ0
	mvi	a,00h
	ret

bdosadr:
	dw	0005h

	else
;NmbSlvs	equ	2
NmbSlvs	equ	1		;BKS TEST
bdosadr:
	dw	$-$
	endif

;  Network Interface Process #0
;
NtwrkIP0:
	dw	0		; link
	db	0		; status
	db	64		; priority
	dw	NtwrkIS0+46	; stack pointer
	db	'NtwrkIP0'	; name
	db	0		; console
	db	0ffh		; memseg
	ds	2		; b
	ds	2		; thread
	ds	2		; buff
	ds	1		; user code & disk slct
	ds	2		; dcnt
	ds	1		; searchl
	ds	2		; searcha
	ds	2		; active drives
	dw	0		; HL'
	dw	0		; DE'
	dw	0		; BC'
	dw	0		; AF'
	dw	0		; IY
	dw	0		; IX
	dw	UQCBNtwrkQI0	; HL
	dw	UQCBNtwrkQO0	; DE
	dw	BufferQ0	; BC
	dw	0		; AF, A = ntwkif console dev #
	ds	2		; scratch

NtwrkIS0:
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	setup

QCBNtwrkQI0:
	ds	2		; link
	db	'NtwrkQI0'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQI0:
	dw	QCBNtwrkQI0	; pointer
	dw	BufferQI0Addr	; msgadr
BufferQI0Addr:
	dw	BufferQ0

QCBNtwrkQO0:
	ds	2		; link
	db	'NtwrkQO0'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQO0:
	dw	QCBNtwrkQO0	; pointer
	dw	BufferQO0Addr	; msgadr
BufferQO0Addr:
	ds	2

BufferQ0:
	ds	1		; FMT
	ds	1		; DID
	ds	1		; SID
	ds	1		; FNC
	ds	1		; SIZ
	ds	256		; MSG

;	Network Interface Process #1
;
	if	NmbSlvs GE 2
NtwrkIP1:
	if	NmbSlvs GE 3
	dw	NtwrkIP2	; link
	else
	dw	0		; link
	endif
	db	0		; status
	db	64		; priority
	dw	NtwrkIS1+46	; stack pointer
	db	'NtwrkIP1'	; name
	db	0		; console
	db	0ffh		; memseg
	ds	2		; b
	ds	2		; thread
	ds	2		; buff
	ds	1		; user code & disk slct
	ds	2		; dcnt
	ds	1		; searchl
	ds	2		; searcha
	ds	2		; active drives
	dw	0		; HL'
	dw	0		; DE'
	dw	0		; BC'
	dw	0		; AF'
	dw	0		; IY
	dw	0		; IX
	dw	UQCBNtwrkQI1	; HL
	dw	UQCBNtwrkQO1	; DE
	dw	BufferQ1	; BC
	dw	0100h		; AF, A = ntwkif console dev #
	ds	2		; scratch

NtwrkIS1:
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	init

QCBNtwrkQI1:
	ds	2		; link
	db	'NtwrkQI1'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQI1:
	dw	QCBNtwrkQI1	; pointer
	dw	BufferQI1Addr	; msgadr
BufferQI1Addr:
	dw	BufferQ1

QCBNtwrkQO1:
	ds	2		; link
	db	'NtwrkQO1'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQO1:
	dw	QCBNtwrkQO1	; pointer
	dw	BufferQO1Addr	; msgadr
BufferQO1Addr:
	ds	2

BufferQ1:
	ds	1		; FMT
	ds	1		; DID
	ds	1		; SID
	ds	1		; FNC
	ds	1		; SIZ
	ds	256		; MSG
	endif

;	Network Interface Process #2
;
	if	NmbSlvs GE 3
NtwrkIP2:
	if	NmbSlvs GE 4
	dw	NtwrkIP3	; link
	else
	dw	0		; link
	endif
	db	0		; status
	db	64		; priority
	dw	NtwrkIS2+46	; stack pointer
	db	'NtwrkIP2'	; name
	db	0		; console
	db	0ffh		; memseg
	ds	2		; b
	ds	2		; thread
	ds	2		; buff
	ds	1		; user code & disk slct
	ds	2		; dcnt
	ds	1		; searchl
	ds	2		; searcha
	ds	2		; active drives
	dw	0		; HL'
	dw	0		; DE'
	dw	0		; BC'
	dw	0		; AF'
	dw	0		; IY
	dw	0		; IX
	dw	UQCBNtwrkQI2	; HL
	dw	UQCBNtwrkQO2	; DE
	dw	BufferQ2	; BC
	dw	0200h		; AF, A = ntwkif console dev #
	ds	2		; scratch

NtwrkIS2:
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	init

QCBNtwrkQI2:
	ds	2		; link
	db	'NtwrkQI2'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQI2:
	dw	QCBNtwrkQI2	; pointer
	dw	BufferQI2Addr	; msgadr
BufferQI2Addr:
	dw	BufferQ2

QCBNtwrkQO2:
	ds	2		; link
	db	'NtwrkQO2'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQO2:
	dw	QCBNtwrkQO2	; pointer
	dw	BufferQO2Addr	; msgadr
BufferQO2Addr:
	ds	2

BufferQ2:
	ds	1		; FMT
	ds	1		; DID
	ds	1		; SID
	ds	1		; FNC
	ds	1		; SIZ
	ds	256		; MSG
	endif

;	Network Interface Process #3
;
	if	NmbSlvs GE 4
NtwrkIP3:
	dw	0		; link
	db	0		; status
	db	64		; priority
	dw	NtwrkIS3+46	; stack pointer
	db	'NtwrkIP3'	; name
	db	0		; console
	db	0ffh		; memseg
	ds	2		; b
	ds	2		; thread
	ds	2		; buff
	ds	1		; user code & disk slct
	ds	2		; dcnt
	ds	1		; searchl
	ds	2		; searcha
	ds	2		; active drives
	dw	0		; HL'
	dw	0		; DE'
	dw	0		; BC'
	dw	0		; AF'
	dw	0		; IY
	dw	0		; IX
	dw	UQCBNtwrkQI3	; HL
	dw	UQCBNtwrkQO3	; DE
	dw	BufferQ3	; BC
	dw	0300h		; AF, A = ntwkif console dev #
	ds	2		; scratch

NtwrkIS3:
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	init

QCBNtwrkQI3:
	ds	2		; link
	db	'NtwrkQI3'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQI3:
	dw	QCBNtwrkQI3	; pointer
	dw	BufferQI3Addr	; msgadr
BufferQI3Addr:
	dw	BufferQ3

QCBNtwrkQO3:
	ds	2		; link
	db	'NtwrkQO3'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

UQCBNtwrkQO3:
	dw	QCBNtwrkQO3	; pointer
	dw	BufferQO3Addr	; msgadr
BufferQO3Addr:
	ds	2

BufferQ3:
	ds	1		; FMT
	ds	1		; DID
	ds	1		; SID
	ds	1		; FNC
	ds	1		; SIZ
	ds	256		; MSG
	endif


	if	WtchDg
;  Watchdog Timer Process
;
WatchDogPD:
	if	NmbSlvs GT 1
	dw	NtwrkIP1	; link
	else
	dw	0		; link
	endif
	db	0		; status
	db	64		; priority
	dw	WatchDogSTK+46	; stack pointer
	db	'WatchDog'	; name
	db	0		; console
	db	0ffh		; memseg
	ds	2		; b
	ds	2		; thread
	ds	2		; buff
	ds	1		; user code & disk slct
	ds	2		; dcnt
	ds	1		; searchl
	ds	2		; searcha
	ds	2		; active drives
	dw	0		; HL'
	dw	0		; DE'
	dw	0		; BC'
	dw	0		; AF'
	dw	0		; IY
	dw	0		; IX
	dw	0		; HL
	dw	0		; DE
	dw	0		; BC
	dw	0		; AF
	ds	2		; scratch

WatchDogSTK:
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h
	dw	WatchDog

WatchDogTime:
	dw	$-$	; one-second counter

WatchDogTable:
	;	Waiting	Timeout	Start	Flag	Slave
	db	0,	0,	0,0,	0ah	; #0
	db	0,	0,	0,0,	0bh	; #1
	db	0,	0,	0,0,	0fh	; #2
	db	0,	0,	0,0,	0dh	; #3
	endif

	if	mutexin or mutexout
QCBMXSXmitq:			; MX queue for slv xmiting
	ds	2		; link
	db	'MXSXmitq'	; name
	dw	0		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer (owner PD)

UQCBMXSXmitq:
	dw	QCBMXSXmitq
;	dw	0
;	db	'MXSXmitq'
	endif

;	Master Configuration Table

configtbl:
	db	0	; Master status byte
	db	0	; Master processor ID
	db	NmbSlvs	; Maximum number of slaves supported
	db	3	; Number of logged in slaves
	dw	000eh	; 16 bit vector of logged in slaves
	db	01
	db	02
	db	03
	ds	13	; Slave processor ID's
	db	'PASSWORD' ; login password
	db	nmbfcbs		; Number of FCB's for each slave
	dw	fcbtable	; Address of table containing fcbs

nmsg	equ	1	; number of messages buffered

;Slave0:		; storage allocated in SLAVESP
;	ds	52	; processor descriptor
;	ds	450	; stack area for reentrant slave sp

	if	NmbSlvs GE 2
Slave1:
	ds	52	; processor descriptor
	ds	450	; stack area for reentrant slave sp
	endif

	if	NmbSlvs GE 3
Slave2:
	ds	52	; processor descriptor
	ds	450	; stack area for reentrant slave sp
	endif

	if	NmbSlvs GE 4
Slave3:
	ds	52	; processor descriptor
	ds	450	; stack area for reentrant slave sp
	endif

	if	mail
;
; Interprocessor Electronic Mail Data Segment
;
MailBox:
	ds	2		; link
	db	'MailBoxQ'	; name
	dw	2		; msglen
	dw	1		; nmbmsgs
	ds	2		; dqph
	ds	2		; nqph
	ds	2		; msgin
	ds	2		; msgout
	ds	2		; msgcnt
	ds	2		; buffer

fcbtable:	ds	40*nmbfcbs*nmbSlvs

MailBoxUQCB:
	dw	MailBox		; pointer
	dw	MailBoxAdr	; msgadr

MailBoxAdr:
	dw	MailBoxes	; Mail Box Data Structure Adr

nmb$mail	equ	4	; # pieces mail max per slave
size$mail	equ	128	; max size per piece of mail
				;  includes two byte overhead of
				;  source ID and size

mail$buffer$size equ	nmb$mail*size$mail

Mail$boxes:
	db	nmb$mail
	db	size$mail

MstrMail:
	db	0	; Master Mail In Ptr
	db	0	; Master Mail Out Ptr
	db	0	; Master Mail Cnt
	dw	MstrMailBuffer	; Master Mail Buffer Adr

Slv0Mail:
	db	0	; Slave #0 Mail In Ptr
	db	0	; Slave #0 Mail Out Ptr
	db	0	; Slave #0 Mail Cnt
	dw	Slv0MailBuffer	; Slave #0 Mail Buffer Adr

	if	NmbSlvs GE 2
Slv1Mail:
	db	0	; Slave #1 Mail In Ptr
	db	0	; Slave #1 Mail Out Ptr
	db	0	; Slave #1 Mail Cnt
	dw	Slv1MailBuffer	; Slave #1 Mail Buffer Adr
	endif

	if	NmbSlvs GE 3
Slv2Mail:
	db	0	; Slave #2 Mail In Ptr
	db	0	; Slave #2 Mail Out Ptr
	db	0	; Slave #2 Mail Cnt
	dw	Slv2MailBuffer	; Slave #2 Mail Buffer Adr
	endif

	if	NmbSlvs GE 4
Slv3Mail:
	db	0	; Slave #3 Mail In Ptr
	db	0	; Slave #3 Mail Out Ptr
	db	0	; Slave #3 Mail Cnt
	dw	Slv3MailBuffer	; Slave #3 Mail Buffer Adr
	endif

MstrMailBuffer:
	ds	mail$buffer$size

Slv0MailBuffer:
	ds	mail$buffer$size

	if	NmbSlvs GE 2
Slv1MailBuffer:
	ds	mail$buffer$size
	endif

	if	NmbSlvs GE 3
Slv2MailBuffer:
	ds	mail$buffer$size
	endif

	if	NmbSlvs GE 4
Slv3MailBuffer:
	ds	mail$buffer$size
	endif
	endif	; matches if mail

;	Local Data Segment
;
BinaryASCII:
	db	0ffh	; Slave #0: 0=7 bit ASCII, FF=8 bit binary
	db	0ffh	;       #1
	db	0ffh	;       #2
	db	0ffh	;       #3

Networkstatus:
	db	0	; Slave #0 network status byte
	db	0	;       #1
	db	0	;       #2
	db	0	;       #3

conin:	dw	$-$	; save area for XIOS routine address

max$retries	equ	10	; maximum send message retries
;
;	The following tables are for use in the ALTOS i/o routines.
;	Note that this program MUST be used with an XIOS which allows
;	using the second printer port as a console port - Accessed as console
;	#4
;
Console4$status equ	02bh
Console3$status	equ	02fh
Console2$status equ	02dh
Printer2$status	equ	029h	; ALSO CONSOLE #4

	if	z80
;
;	ENTRIES IN THE FOLLOWING TWO TABLES MUST MATCH !!!!
;
status$ports:
	db	Console4$status ; Console 4 (Slave 0) status port
	db	Console3$status	; Console 3 (Slave 1) status port
	db	Console2$status	; Console 2 (Slave 2) status port
	db	Printer2$status	; Printer 2 (Slave 3) status port
	endif

chariotbl:			; Relationship between slaves and consoles
	db	3
	db	2
	db	1
	db	4
;	Network Status Byte Equates
;
ntwrktxrdy	equ	10000000b	; ntwrk I/F ready to send msg
active		equ	00010000b	; slave logged into network
msgerr		equ	00001000b	; error in received message
ntwrk		equ	00000100b	; network alive
msgovr		equ	00000010b	; message overrun
ntwrkrxrdy	equ	00000001b	; ntwrk I/F has rcvd msg

;	BDOS and XDOS Equates
;
flagset	equ	133	; flag set
makeq	equ	134	; make queue
readq	equ	137	; read queue
writeq	equ	139	; write queue
delay	equ	141	; delay
dsptch	equ	142	; dispatch
createp	equ	144	; create process
sydatad	equ	154	; system data page address
poll	equ	083h	; Poll device

;	General Equates
;
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
LF	equ	0ah	; Line Feed
CR	equ	0dh	; Carriage Return
NAK	equ	15h	; Negative Acknowledge

printer2	equ	10h	; special poll device number for second 
				; printer port

;	Utility Procedures
;
bdos:
	lhld	bdosadr
	pchl

Nibout:			; A = nibble to be transmitted in ASCII
	cpi	10
	jnc	nibatof	; jump if A-F
	adi	'0'
	mov	c,a
	jmp	Charout
nibatof:
	adi	'A'-10
	mov	c,a
	jmp	Charout

PreCharout:
	mov	a,d
	add	c
	mov	d,a	; update the checksum

	if	z80
char$out:
;
;	Character output routine for network i/o
;	using the ALTOS SIO ports
;
;	Entry: C register contains 8 bit value to transmit
;	Entry : Slave number in register b

	push	h
	push	d
	push	b
	mov	d, c		; save the character
	lxi	h, status$ports
	mov	c, b
	mvi	b, 0		; set (BC) = (b)
	dad	b
	mov	c,m
	; Now C contains the address of the correct status port
outputloop:
	mvi	a, 10h
	outp	a
	inp	a
	ani	04h		; wait for TXready
	jrz	outputloop

	; In the Altos system, data registers are one below status registers...
	dcr	c
	outp	d
	pop	b
	pop	d
	pop	h
	ret

	else

char$out:
;	Character output routine for network I/O
;	using ALTOS SIO ports
;
;	Entry:	C = character to transmit
;		B = slave id byte

	push 	h
	push	d
	push	b

	lxi	d,out0			; dispatch address = 
	mov	l,b			;   out0 + slaveid*16
	mvi	h,0
	dad	h
	dad	h
	dad	h
	dad	h
	dad	d
	mvi	a,10h			;load "get transmit status" value
	pchl				;dispatch 

out0:
	out	Console4$status		;wait for TXready status
	in	Console4$status
	ani	4
	jz	out0

	mov	a,c
	out	Console4$status-1	;write the character
	pop	b
	pop	d
	pop	h
	ret

out1:	out	Console3$status
	in	Console3$status
	ani	4
	jz	out1

	mov	a,c
	out	Console3$status-1
	pop	b
	pop	d
	pop	h
	ret

out2:	out	Console2$status
	in	Console2$status
	ani	4
	jz	out2

	mov	a,c
	out	Console2$status-1
	pop	b
	pop	d
	pop	h
	ret

out3:	out	Printer2$status
	in	Printer2$status
	ani	4
	jz	out3

	mov	a,c
	out	Printer2$status-1
	pop	b
	pop	d
	pop	h
	ret

	endif


;

Nibin:		; return nibble in A register
	call	Charin
	rc
	ani	07fh
	sui	'0'
	cpi	10
	jc	Nibin$return ; must be 0-9
	adi	('0'-'A'+10) and 0ffh
	cpi	16
	jc	Nibin$return ; must be 10-15
	lda	networkstatus
	ori	msgerr
	sta	networkstatus
	mvi	a,0
	stc
	ret
Nibin$return:
	ora	a
	ret

xChar$in:
;
	push	h
	push	b
	lxi	h, Charin$return
	push	h
	mov	c,b
	mvi	b,0
	lxi	h, chariotbl
	dad	b
	mov	d, m	; Get the console number
	lhld	conin
	pchl		; vector off
Charin$return:
	pop	b
	pop	h
	ret


	if	z80
char$in:
;
;	Character input routine for network i/o
;	using the ALTOS SIO ports at 125k baud
;
;	
;	Entry : Slave number in register b
;	Exit  : Character in register a
;
	push	h
	push	b
	lxi	h, status$ports
	mov	c, b
	mvi	b, 0		; set (BC) = (b)
	dad	b
	mov	c,m
	; Now C contains the address of the correct status port
	mvi	l, 80
inputloop1:
	dcr	l
	jrz	retout
	inp	a
	ani	01h		; wait for RXready
	jrz	inputloop1

	; In the Altos system, data registers are one below status registers...
	dcr	c
	inp	a	; Get the character
	pop	b
	pop	h
	ret

retout:
	stc		;set carry => error flag
	pop	b
	pop	h
	ret

	else

char$in:
;	Character input routine for network I/O
;	using ALTOS SIO ports
;
;	Entry:	B = Slave ID
;	Exit:	A = character input

	push 	h
	push	d
	push	b
	lxi	d,in0			; HL = in0 + 17*slaveid
	mov	l,b
	mvi	h,0
	xchg
	dad	d
	xchg
	dad	h
	dad	h
	dad 	h
	dad	h
	dad	d

	mvi	c,80			; load status retry count
	pchl				; dispatch

in0:
	dcr	c
	jz	retout			; error return if retry timeout

	in	Console4$status		; wait for RXready
	ani	1
	jz	in0

	in	Console4$status-1	; get the character
	pop	b
	pop	d
	pop	h
	ret

in1:
	dcr	c
	jz	retout			; error return if retry timeout

	in	Console3$status		; wait for RXready
	ani	1
	jz	in1

	in	Console3$status-1	; get the character
	pop	b
	pop	d
	pop	h
	ret

in2:
	dcr	c
	jz	retout			; error return if retry timeout

	in	Console2$status		; wait for RXready
	ani	1
	jz	in2

	in	Console2$status-1	; get the character
	pop	b
	pop	d
	pop	h
	ret
in3:
	dcr	c
	jz	retout			; error return if retry timeout

	in	Printer2$status		; wait for RXready
	ani	1
	jz	in3

	in	Printer2$status-1	; get the character
	pop	b
	pop	d
	pop	h
	ret

retout:					; error return (carry=1)
	stc
	pop	b
	pop	d
	pop	h
	ret

	endif


Netout:	; C = byte to be transmitted
	mov	a,d
	add	c
	mov	d,a
	lda	BinaryASCII
	ora	a
	jnz	Charout	; transmit byte in Binary mode
	mov	a,c
	push	psw
	rar
	rar
	rar
	rar
	ani	0FH	; mask HO nibble to LO nibble
	call	Nibout
	pop	psw
	ani	0FH
	jmp	Nibout

Netin:		; byte returned in A register
		; D  = checksum accumulator
	lda	BinaryASCII
	ora	a
	jz	ASCIIin
	call	charin	;receive byte in Binary mode
	rc
	jmp	chksin
ASCIIin:
	call	Nibin
	rc
	add	a
	add	a
	add	a
	add	a
	push	psw
	call	Nibin
	rc
	xthl
	ora	h
	pop	h
chksin:
	ora	a
	push	psw
	add	d	; add & update checksum accum.
	mov	d,a
	pop	psw
	ret

Msgin:		; HL = destination address
		; E  = # bytes to input
	call	Netin
	rc
	mov	m,a
	inx	h
	dcr	e
	jnz	Msgin
	ret

Msgout:	; HL = source address
	; E  = # bytes to output
	; D  = checksum
	; C  = preamble character
	mvi	d,0
	call	PreCharout
Msgoutloop:
	mov	c,m
	inx	h
	call	Netout
	dcr	e
	jnz	Msgoutloop
	ret

;	Network Initialization
nwinit:
;	device initialization, as required
;
;
	mvi	a,047h		;sets up CTC for baud rate of 125k
	out	031h
	out	030h
	out	032h
	mvi	a,1		;count of one => max speed
	out	031h
	out	030h		; slave #1 ctc channel
	out     032h
;
;	Find address of XIOS console output routine
;
	lhld	0001h
	inx	h
	mov	e, m
	inx	h
	mov	d, m
	lxi	h, 0006h	; Offset for conin routine
	dad	d
	shld	conin		; save the address
	xra	a		;return code is 0=success
	ret


;	Network Status
nwstat:		; C = Slave #
	mvi	b,0
	lxi	h,networkstatus
	dad	b
	mov	a,m
	mov	b,a
	ani	not (msgerr+msgovr)
	mov	m,a
	mov	a,b
	ret


;	Return Configuration Table Address
cfgadr:
	lxi	h,configtbl
	ret


;	Send Message on Network
sndmsg:			; DE = message addr
			;  C = Slave #
	mov	b,c
	mvi	a,max$retries	; A = max$retries
send:
	push	psw

	if	mutexout
	push	b
	push	d
	mvi	c,readq
	lxi	d,UQCBMXSXmitq
	call	bdos	; obtain mutual exclusion message
	pop	d
	pop	b
	endif

	xchg
	push	h
	di
	mvi	c,ENQ
	call	Charout	; send ENQ
	call	getACK
	mvi	e,5
	mvi	c,SOH
	call	Msgout	; send SOH FMT DID SID FNC SIZ
	xra	a
	sub	d
	mov	c,a
	call	Netout	; send HCS (header checksum)
	call	getACK
	dcx	h
	mov	e,m
	inx	h
	inr	e
	mvi	c,STX
	call	Msgout	; send STX DB0 DB1 ...
	mvi	c,ETX
	call	PreCharout	; send ETX
	xra	a
	sub	d
	mov	c,a
	call	Netout	; send CKS
	mvi	c,EOT
	call	PreCharout	; send EOT
	call	getACK
	pop	d	; discard message address
	pop	psw	; discard retry counter

	if	mutexout
	call	release$MX
	endif

	ei
	xra	a
	ret		; A = 0, successful send message

getACK:
	call	Charin
	jc	getACK$timeout
	ani	7fh
	sui	ACK
	rz
getACK$timeout:
	pop	d	; discard return address

	if	mutexout
	push	b
	call	release$MX
	pop	b
	endif

	pop	d	; DE = message address
	pop	psw	; A = retry count
	dcr	a
	jnz	send
	dcr	a	; A = 0ffh
	ret		; failed to send message

	if	mutexin or mutexout
release$MX:
	; send back slave transmit MX message
	mvi	c,writeq
	lxi	d,UQCBMXSXmitq
	jmp	bdos
	endif

;	Receive Message from Network
rcvmsg:			; DE = message addr
			;  C = Slave #
	mov	b,c
receive:
	xchg
	push	h
	call	get$ENQ
	; a return to this point indicates an error

receive$retry:
	ei		;enable other processes

	if	mutexin
	push	b
	call	release$MX
	pop	b
	endif

	pop	d
	jmp	receive

get$ENQ:
	call	xCharin
	jc	get$ENQ
	ani	7fh
	cpi	ENQ	; Start of Header ?
	jnz	get$ENQ

	if	mutexin
	;get the slave xmit MX message before allowing slv to xmit
	push	b
	push	h
	mvi	c,readq
	lxi	d,UQCBMXSXmitq
	call	bdos
	pop	h
	pop	b
	endif

	mvi	c,ACK
	di		;slave in gear now serve only him

	call	charout	; send ACK to slave, allows it to xmit
	call	Charin
	rc
	ani	7fh
	cpi	SOH
	rnz
	mov	d,a	; initialize the HCS
	mvi	e,5
	call	Msgin
	cnc	Netin
	rc
	mov	a,d
	ora	a
	jnz	sendNAK	; jmp & send NAK if HCS <> 0
	mvi	c,ACK
	call	Charout
	call	Charin
	rc
	ani	7fh
	cpi	STX
	rnz
	mov	d,a	; initialize the CKS
	dcx	h
	mov	e,m
	inx	h
	inr	e
	call	msgin
	cnc	Charin
	rc
	ani	7fh
	cpi	ETX
	rnz
	add	d
	mov	d,a
	call	Netin	; get Checksum byte
	rc
	mov	a,d
	ora	a	; should be zero
	jz	sendACK	; jump if checksum OK
sendNAK:
	mvi	c,NAK
	jmp	Charout	; send NAK and return to receive$retry
sendACK:
	call	Charin	; get EOT
	rc
	ani	7fh
	cpi	EOT
	rnz
	mvi	c,ACK
	call	Charout	; send ACK if checksum ok
	pop	d	; discard return address
	pop	d	; discard message address
	ei		; now allow multiprocessing

	if	mutexin
	call	release$MX
	endif

	xra	a
	ret



restore:
	di
	pop	h
	shld	rtnadr
	pop	h
	pop	d
	pop	b
	pop	psw
	push	psw
	push	b
	push	d
	push	h
	push	h
	lhld	rtnadr
	xthl
	ei
	ret
rtnadr:	ds	2

	if	WtchDg
;  WatchDog Timer Process
;
WatchDog:
	mvi	c,Delay
	lxi	d,60	; dly for 1 second
	call	bdos
	lhld	WatchDogTime
	inx	h
	shld	WatchDogTime
	lxi	h,WatchDogTable-5
	mvi	c,NmbSlvs
WatchDogLoop:
	lxi	d,0005h
	dad	d
	mov	a,m
	ora	a
	jz	WatchDogDec
	inx	h
	ana	m
	dcx	h
	jnz	WatchDogDec	; waiting & timeout set
	push	h		; save HL -> WDT.waiting
	inx	h
	inx	h
	di
	mov	e,m
	inx	h
	mov	d,m
	ei
	lhld	WatchDogTime
	mov	a,l
	sub	e
	mov	l,a
	mov	a,h
	sbb	d
	mov	h,a
	mvi	a,10	; # seconds since started Charinn
	sub	l
	mvi	a,0
	sbb	h
	pop	h
	jnc	WatchDogDec
	push	h
	inx	h
	mvi	m,0ffh	; WDT.timeout = 0ffh
	inx	h
	inx	h
	inx	h
	push	b
	mov	e,m	; E = Flag #
	mvi	c,Flagset
	call	bdos
	pop	b
	pop	h

WatchDogDec:
	dcr	c
	jnz	WatchDogLoop

	jmp	WatchDog
	endif

;
;	Setup code for Network Interface Procedures
;
Setup:
	push	psw
	push	b
	push	d
	push	h
	call	nwinit

	if	mutexin or mutexout
	mvi	c,makeq
	lxi	d,QCBMXSXmitq
	call	bdos
	mvi	c,writeq
	lxi	d,UQCBMXSXmitq
	call	bdos
	endif

	if	mail
	mvi	c,makeq
	lxi	d,MailBox
	call	bdos
	mvi	c,writeq
	lxi	d,MailBoxUQCB
	call	bdos
	endif

	if	WtchDg
	lxi	d,WatchDogPD
	mvi	c,createp
	call	bdos
	else
	if	NmbSlvs GE 2
	lxi	d,NtwrkIP1
	mvi	c,createp
	call	bdos
	endif
	endif

	mvi	c,dsptch
	call	bdos
	mvi	c,sydatad
	call	bdos
	lxi	d,9
	dad	d
	lxi	d,configtbl
	mov	m,e
	inx	h
	mov	m,d	; sysdatpage(9&10) = co.configtbl

	if	modem
	; Initialize the modem
	mvi	c,CR
	mvi	b,slvmodem
	call	Charout
	mvi	c,'Z'
	call	Charout
	mvi	c,CR
	call	Charout
WtSpace:
	call	Charin
	jc	SetupDone
	ani	07fh
	cpi	' '
	jnz	WtSpace
	mvi	c,'A'
	call	Charout
SetupDone:
	endif

	pop	h
	pop	d
	pop	b
	pop	psw
;
;  Network Interface Reentrant Procedure
;
Init:
	push	psw	; A = network i/f console dev #
	push	B	; BC= buffer address
	push	D	; DE= UQCB ntwrk queue out
	push	H	; HL= UQCB ntwrk queue in
	mov	e,m
	inx	h
	mov	d,m
	mvi	c,makeq
	call	bdos	; make the ntwrk queue in
	call	restore
	xchg
	mov	e,m
	inx	h
	mov	d,m
	mvi	c,makeq
	call	bdos	; make the ntwrk queue out

Loop:
	call	restore
	mov	d,b
	mov	e,c
;
;
	mov	c,a
	call	rcvmsg

	call	restore
	xchg
	mvi	c,writeq
	call	bdos

	call	restore
	mvi	c,readq
	call	bdos

	call	restore
	mov	d,b
	mov	e,c
;
	mov	c,a
	call	sndmsg

	jmp	Loop

	end
