;//////////////////////////////////////////////////////////////////////////////
;
     TITLE  'MEX Overlay for Toshiba T100 and Serial Interface Adapter '
;
;	NOTE - this overlay is designed to be specific for a Toshiba T00
;	together with a Hayes Smartmodem 300/1200 driven in conjunction with
;	a Toshiba Support Group Serial Async Interface Adapter. 
;
;	--- A very good starting point for ANY 2651 usart IO device, however.
;	 
;//////////////////////////////////////////////////////////////////////////////
;
REV	EQU	10		; revision number * 10
;
;******************************************************************************
;
;	One problem with the Toshiba T100 is the inabillity to do 1200
;	bps. This is due to the fact that Toshiba, for some reason - which is
;	completely beyond comprehension of civilized man - had decided to 
;	implement a software usart on an 8255 PIA. It is impossible to get 
;	1200 bps out of the infernal thing. Need I say that 300 bps gets
;	a bit frustrating to sysops, including myself. Well, to solve the
;	problem, I've designed a serial interface with a National INS2651 
;	usart to get up to 19.2K baud out of the Tosh. (I don't own a Tosh, 
;	but I got tired of all of the bitching about not being able to do 
;	1200 with the thing). Tha adapter plugs into the rampack 2 expansion 
;	slot. You still can use slot 1 for the prom expansion. 
;
;	Tosh does furnish a serial port adapter - matter of fact, they are 
;	glad to sell you one. So would I at $400.00+ - arrghhhh ... gag me with
;	a microchip.... whats that old saying coined by Ward.....
;
;			   Sempus Non Rippus Offis
;
;	My adapter goes for about 40 bucks (+/-) in small quanity. If there 
;	is a demand for it, this will be reduced as it costs a lot less to 
;	build 100 of 'em than it does 10. If you are 1) a poor soul with a 
;	Tosh, 2) are tired of paying Ma Bell and 3) would really like to do 
;	1200/2400 all the way up to 19,200 (dream on, we all wish...) baud on 
;	dialups, then contact me, the Sysop at Smokin Silicon RCP/M to leave 
;	a private message in 'TOS' - Ill get back to you. Smokin Silicon is 
;	the central point for the Toshiba Support group. If Toshiba won't 
;	support it at a reasonable price, We will. I'll be happy to fill yall 
;	in on the details. Flawless performance in computer <=> computer batch 
;	xfers with MEX at 9600 bps. This is the first in a series of RCPM 
;	overlays to support the serial adapter and the machine. 
;
;					    modem to the max / happy hacking
;			
;						    JP Sojak - sysop -
;					           Smokin Silicon RCP/M
;					           (312)941-0049 24 hrs 
;
;  ps - if you have a special problem with your machine, Ill try to help out.
;       By helping you out, many benifit. (Sempus Non Rippus Offis - FIGHT
;	BACK - don't put up with the garbage many manufactures try to feed 
;	you) 
;	
;******************************************************************************
;
;  02/24/84 ... mxo-tsa.asm   (for TS A-dapter)
;
;		Base version for a Toshiba T100 and a serial adapter. Roots
;		are everywhere by a cast of thousands. Thanks all... 
;		- Especially Ron Fowler for doing the single most important
;		public domain work since the original Modem7
;		
;						    		JP Sojak 
;
;//////////////////////////////////////////////////////////////////////////////
;
;	There is a Zilog SIO style full featured SET command implemented on
;	the INS2651 USART device ... The SET is specific to Smartmodem 
;	compatables. The available commands are:
;
;	delay <n> (seconds) .... SET the delay between dial and "NO CARRIER"
;	baud <rate> 110-19.2k .. SET the baud rate 110-19.2K, no 450 and 710
;	orig (originate mode) .. SET the modem originate (callout) carrier 
;	answer	(answer mode) .. SET the modem answer (callin) carrier 
;	tone ................... SET touch tone dialing
;	pulse .................. SET pulse dialing
;       monitor ................ SET the speaker ON
;	quiet .................. SET the speaker OFF
;	parity ................. SET the parity to odd, even, or none
;	stop ................... SET 1, 1.5, or 2 stopbits
;	bits ................... SET 5, 6, 7, or 8 bit data word length
;	digit .................. SET the interdigit dial time in mS 
;
;	"SET" <cr> will bring up the current settings.
;	"SET ?"<cr> will bring up the syntax for the SET commands available. 
;	And additionally, all 'SET'tings are 100% cloneable to new defaults.
;
;//////////////////////////////////////////////////////////////////////////////
;
; adapter port definitions
;
BASEP	EQU	018H		; port base address
DATAPT	EQU	BASEP		; serial data port
SPORT	EQU	BASEP+1		; status register
MODE1	EQU	BASEP+2		; first mode register
MODE2	EQU	BASEP+2		; second mode register
CPORT	EQU	BASEP+3		; command register
;	
;
; 2651 usart bit definitions
;
MDRCVB	EQU	00000010B	; modem receive bit (dav)
MDRCVR	EQU	00000010B	; modem receive ready
MDSNDB	EQU	00000001B	; modem send bit
MDSNDR	EQU	00000001B	; modem send ready bit
MDMDTR	EQU	00000010B	; modem data trm ready bit
;
; PLEASE NOTE ... The use of DCD (Data Carrier Detect) status register bit
; within the USART should be avoided. It is actually a Tx enable for the
; hardware. It MUST be pulled high on the EIA cable or the USART will seem
; to "hang". When it is active, the initialization routine thinks there 
; is returning from CP/M with a carrier present even when there isnt - 
; improper switch settings could unconditionally force an active (HIGH) state 
; - and abort the routine. The adapter has been defaulted with a pullup to 
; avoid "hanging" the hardware if the DCD #8 is left unconnected. It is 
; desirable to redefine the carrier sence bit to DSR #6 (Data Set Ready). It 
; is customary to leave DCD #8 open on the interface side and connect DCD #8 
; from the modem to DSR #6 (Data Set Ready) on the interface side. In this 
; way, the USART will never "hang". If you wish to use DCD then by all means 
; do so. As a matter of fact, ANY rcpm work REQUIRES it, but if you do not
; follow what all of this is about, then it is best to leave the equate as 
; is and prepare a cable as follows.... 
;
;	MODEM			 INTERFACE
;	(DCE)			   (DTE)
;
;	#1 <------------------------> #1  water pipe ground (optional)
;	#2 <------------------------> #2  \
;					   (Tx and Rx data)
;	#3 <------------------------> #3  / 
;
;	#7 <------------------------> #7  Signal Ground
; (DCD)	#8 <------------------------> #6  Data Set Ready
;      #20 <------------------------> #20 Data Terminal Ready
;
;
;MDMDCD	EQU	01000000B	; DCD used to sence carrier present 
;
MDMDCD	EQU	10000000B	; DSR used to sence a carrier present 	
;
;
;******************************************************************************
;
; Status register definitions within the 8251 USART device:
;
;	MODE 0 REGISTER (base + 2)
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;  | 00 - invalid    | X0 - no parity  | 00 - 5 bits     |     must be     |
;  | 01 - 1 stop     | 01 - odd        | 01 - 6 bits     |   1    |   0    |
;  | 10 - 1.5 stop   | 10 - no parity  | 10 - 7 bits     | for the adapter |
;  | 11 - 2 stops    | 11 - even       | 11 - 8 bits     |        |        |
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;
;	MODE 1 REGISTER (base + 2)
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;  |        |        |     must be     | internal baud rate select register|
;  |   X    |   X    |   1    |   1    |        +        +        +        |
;  |        |        |  for the adapter|   B3   |   B2   |   B1   |   B0   |
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;
; Where the internal generator is selected and is represented by:
;
;	NOTE - some of these are NOT supported by MEX - the USART does em,
;		but MEX has no idea they exist.
;	
;   Bx=	3 2 1 0			|  3 2 1 0
;   ----------------------------+-------------------------------
;	0 0 0 0 .... 50 baud	|  0 0 0 1 .... 75 baud
;	0 0 1 0 .... 110 baud	|  0 0 1 1 .... 134.5 baud
;	0 1 0 0 .... 150 baud	|  0 0 0 1 .... 300 baud
;	0 1 1 0 .... 600 baud	|  0 1 1 1 .... 1200 baud
;	1 0 0 0 .... 1800 baud	|  1 0 0 1 .... 2000 baud
;	1 0 1 0 .... 2400 baud	|  1 0 1 1 .... 3600 baud
;	1 1 0 0 .... 4800 baud  |  1 1 0 1 .... 7200 baud
;	1 1 1 0 .... 9600 baud	|  1 1 1 1 .... 19.2K baud
; 	
;	COMMAND	REGISTER (base + 3)
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;  | 00 - normal     | RTS    | ERROR  | FORCE  | RECV   | DTR    | TRNSMT |
;  | 01 - auto echo  | CTRL   | RESET  | BREAK  | CTRL   | CTRL   | CTRL   |
;  | 10 - lcl lopbak | 0 - hi | 0 -norm| 0 -norm| 0 -dsbl| 0 -hi  | 0 -dsbl|
;  | 11 - rmt lopbak | 1 - lo | 1 -rst | 1 -brk | 1 -enbl| 1 -lo  | 1 -enbl|
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;
;	STATUS REGISTER (base + 1)
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;  |        |        | FRAME  | OVERRUN| PARITY |Tx SHIFT| Rx CHAR| Tx BUFR|
;  | DSR lo | DCD lo | ERROR  | ERROR  | ERRORY |REGISTER| READY  |  EMPTY |
;  |        |        |        |        |        | EMPTY  |        |        |
;  +--------+--------+--------+--------+--------+--------+--------+--------+
;
;	MODE 1 register must be written into before MODE 2 - it is a toggle 
;	type operation. a COMMAND register <read> operation will reset the
;	toggle so the next MODE operation will be performed on the first 
;	register - REGISTER 1.
;
;******************************************************************************
;
; standard mex service processor hooks
;
MEX	EQU	0D00H		;address of the service processor
INMDM	EQU	255		;get char from port to a, cy=no more in 100 ms
TIMER	EQU	254		;delay 100ms * reg b
TMDINP	EQU	253		;b=# secs to wait for char, cy=no char
CHEKCC	EQU	252		;check for ^c from kbd, z=present
SNDRDY	EQU	251		;test for modem-send ready
RCVRDY	EQU	250		;test for modem-receive ready
SNDCHR	EQU	249		;send a character to the modem (after sndrdy)
RCVCHR	EQU	248		;recv a char from modem (after rcvrdy)
LOOKUP	EQU	247		;table search: see cmdtbl comments for info
PARSFN	EQU	246		;parse filename from input stream
BDPARS	EQU	245		;parse baud-rate from input stream
SBLANK	EQU	244		;scan input stream to next non-blank
EVALA	EQU	243		;evaluate numeric from input stream
LKAHED	EQU	242		;get nxt char w/o removing from input
GNC	EQU	241		;get char from input, cy=1 if none
ILP	EQU	240		;inline print
DECOUT	EQU	239		;decimal output
PRBAUD	EQU	238		;print baud rate
;
CONOUT	EQU	2		;simulated bdos function 2: console char out
PRINT	EQU	9		;simulated bdos function 9: print string
INBUF	EQU	10		;input buffer, same structure as bdos 10
;
; msc crud
;
TPA	EQU	100H
CR	EQU	13
LF	EQU	10
TAB	EQU	9
DING	EQU	'G'-40H
;
YES	EQU	0FFFFH		;it is so
NO	EQU	NOT YES 	;it is not so
;
;//////////////////////////////////////////////////////////////////////////////
;
	ORG	TPA
;
;//////////////////////////////////////////////////////////////////////////////
;
	DS	3		;mex has a jmp start here
	DS	2		;not used by mex
TPULSE:	DB	'T'		;t=touch, p=pulse (used by this overlay)
CLOCK:	DB	40		;clock speed x 10 (up to 25.5 mhz.)
MSPEED:	DB	5		;sets display time for sending a file
				;0=110	1=300  2=450  3=600  4=710
				;5=1200 6=2400 7=4800 8=9600 9=19200
BYTDLY:	DB	5		;default time to send character in
				;terminal mode file transfer (0-9)
				;0=0 delay, 1=10 ms, 5=50 ms, 9=90 ms
CRDLY:	DB	5		;end-of-line delay after crlf in terminal
				;mode file transfer for slow bbs systems
				;0=0 delay, 1=100 ms, 5=500 ms, 9=900 ms
COLUMS:	DB	5		;number of directory columns
SETFL:	DB	YES		;yes=user-defined set command
SCRTST:	DB	YES		;yes=if home cursor and clear screen
				;routine at clrscrn
	DB	0		;was once acknak, now spare
BAKFLG:	DB	YES		;yes=make .bak file
CRCDFL:	DB	YES		;yes=default to crc checking
				;no=default to checksum checking
TOGCRC:	DB	YES		;yes=allow toggling of checksum to crc
CVTBS:	DB	NO		;yes=convert backspace to rub
TOGLBK:	DB	YES		;yes=allow toggling of bksp to rub
ADDLF:	DB	NO		;no=no lf after cr to send file in
				;terminal mode (added by remote echo)
TOGLF:	DB	YES		;yes=allow toggling of lf after cr
TRNLOG:	DB	NO		;yes=allow transmission of logon
				;write logon sequence at location logon
SAVCCP:	DB	YES		;yes=do not overwrite ccp
LOCNXT:	DB	NO		;yes=local cmd if extchr precedes
				;no=not local cmd if extchr precedes
TOGLOC:	DB	YES		;yes=allow toggling of locnxtchr
LSTTST:	DB	YES		;yes=allow toggling of printer on/off
				;in terminal mode. set to no if using
				;the printer port for the modem
XOFTST:	DB	NO		;yes=allow testing of xoff from remote
				;while sending a file in terminal mode
XONWT:	DB	NO		;yes=wait for xon after sending cr while
				;transmitting a file in terminal mode	
TOGXOF:	DB	YES		;yes=allow toggling of xoff testing
IGNCTL:	DB	NO 		;yes=do not send control characters
				;above ctl-m to crt in terminal mode
				;no=send any incoming ctl-char to crt
EXTRA1:	DB	0		;for future expansion
EXTRA2:	DB	0		;for future expansion
BRKCHR:	DB	'@'-40H		;^@ = send a 300 ms. break tone
NOCONN:	DB	'N'-40H		;^n = disconnect from phone line
LOGCHR:	DB	'L'-40H		;^l = send logon
LSTCHR:	DB	'P'-40H		;^p = toggle printer
UNSVCH:	DB	'R'-40H		;^r = close input text buffer
TRNCHR:	DB	'T'-40H		;^t = transmit file to remote
SAVCHR:	DB	'Y'-40H		;^y = open input text buffer
EXTCHR:	DB	'^'-40H		;^^ = send next character
;
	DS	2		;not used
;
; low-level modem i/o routines.
;
INCTL1:	JMP	INC		;in modem control port
	DB	0,0,0,0,0,0,0	;spares if needed for non-pmmi
;
OTDATA:	JMP	OUTD		;out modem data port
	DB	0,0,0,0,0,0,0	;spares if needed for non=pmmi
;
INPORT: JMP	IND		;in modem data port
	DB	0,0,0,0,0,0,0	;spares if needed for non-pmmi
;
; bit-test routines. 
;
MASKR:	ANI MDRCVB ! RET	;bit to test for receive ready
TESTR:	CPI MDRCVR ! RET	;value of receive bit when ready
MASKS:	ANI MDSNDB ! RET	;bit to test for send ready
TESTS:	CPI MDSNDR ! RET	;value of send bit when ready
;
	DS	12
;
LOGON:	DS	2		;needed for mdm compat, not ref'D BY MEX
DIALV:	JMP	DIAL
DISCV:	JMP	DISCON
GOODBV:	JMP	GOODBYE		;called before exit to cp/m
INMODV:	JMP	NITMOD		;initialization. called at cold-start
NEWBDV:	JMP	PBAUD		;set baud rate
NOPARV:	RET!NOP!NOP		;set modem for no-parity
PARITV:	RET!NOP!NOP		;set modem parity
SETUPV:	JMP	SETCMD		;set cmd: jump to a ret if you don'T WRITE SET
SPMENV:	RET!NOP!NOP		;not used with mex
VERSNV:	JMP	SYSVER		;overlay'S VOICE IN THE SIGN-ON MESSAGE
BREAKV:	JMP	SBREAK		;send a break
;
; mdm calls supported in mex 1.0 but not recommended for use.
;
ILPRTV:	DS	3		;replace with mex function 9
INBUFV:	DS	3		;replace with mex function 10
ILCMPV:	DS	3		;replace with table lookup funct. 247
INMDMV:	DS	3		;replace with mex function 255
NXSCRV:	DS	3		;not supported by mex (returns w/no action)
TIMERV:	DS	3		;replace with mex function 254
;
; terminal specific control sequences
;
; if you wish to use the terminal screen operations, uncomment the code below 
; and insert your terminal specific routines at the clsmsg and eosmsg string 
; areas.
;	
CLREOS:		
;	lxi	d,eosmsg
;	mvi	c,print
;	call	mex
	RET
;
CLS:	
;	lxi	d,clsmsg
;	mvi	c,print
;	call	mex
	RET
;
; put your terminal specific strings here ... (I don't know what they are) 
;	... dont forget the '$'
;
EOSMSG:	  DB	17H,'$'		;clear to end-of-screen
CLSMSG:	  DB	1AH,'$'		;clear whole screen
;
;------------------------------------------------------------
;
; input control/status port
;
INC:	IN	SPORT		; get the status bits
	RET
;
; input data port
;
IND:	IN	DATAPT		
	RET
;
; output data port
;
OUTD:	OUT	DATAPT
	RET
;
; print out the overlay version
;
SYSVER:	  CALL	MILP
	  DB	'Toshiba Support Group Serial Interface',CR,LF
;	  DB	'Trashiba T100 - V' 	;he.. he.. he...
	  DB	'Toshiba T100 - V'	
	  DB	REV/10+'0'
	  DB	'.'
	  DB	REV MOD 10+'0'
	  DB	CR,LF
	  DB    0
	  RET
;
; send break routine
;
SBREAK: 
;
; disconnect routine
;
DISCON:   
;
; goodbye routines are called by mex prior to exit to cp/m
;
GOODBYE:MVI	A,00011101B	; drop cts, dtr and force break a
	OUT	CPORT
	MVI	B,3		; 300 ms
	CALL	MTIME
	MVI	A,00100111B	; initial default
	OUT	CPORT
	RET
;
; initialize rs-232 to default modes.
;
NITMOD: CALL	INC		;see if carrier ie returning to mex with
	ANI	MDMDCD		;a call active 
	RNZ			;skip if connected

	LDA	SPEED		; load default ascii baud rate 
	STA	MSPEED		;and keep it current
	CALL	PBAUD		;set the baud rate
;
; default the modem to either speaker ON or OFF - as CLONED
;
	LDA	MONFLG		;get monitor default
	ORA	A
	MVI	A,'0'		;speaker off
	JZ	NIT4
	MVI	A,'1'		;speaker on

NIT4:  	STA	SMINIT+3	;put it in sminit string
;
; default the modem mode to either answer or originate - as CLONED
; 
	LDA	ANSFLG		;get mode default
	ORA	A
	MVI	A,'0'		;originate
	JZ	NIT5
	MVI	A,'1'		;answer

NIT5:  	STA	S0NIT+3		;put it in sminit string
;
; set up the modem with the initial string 
;	
	LXI	H,SMINIT
SINIT:	CALL	SMSEND		;send the init string
SMTLP1:	MVI	C,INMDM		;wait for modem response
	CALL	MEX
	JNC	SMTLP1		;eat everything until silence for
	RET			; 100 msec
;
; set command processor
;
SETCMD:	  MVI	C,SBLANK	;any arguments?
	  CALL  MEX
	  JC	SETSHO		;if not, display default(s)
	  LXI	D,CMDTBL
          MVI	C,LOOKUP
	  CALL  MEX		;parse the argument
	  PUSH	H		;save any parsed arguments on stack
	  RNC			;if we have one, return to it
	  POP	H		;oops, input not found in table
SETERR:	  LXI	D,SETEMS
	  MVI	C,PRINT
	  CALL	MEX
	  CALL  CRLF
	  RET
SETEMS:	  DB	CR,LF,'Unrecognized SET command',DING,CR,LF,'$'
;
SETBAD:	  LXI	D,SETBMS
	  MVI	C,PRINT
	  CALL	MEX
	  RET
SETBMS:	  DB	CR,LF,'Invalid SET parameter',DING,CR,LF,'$'
;
; argument table
;
CMDTBL:   DB	'?'+80H			; help
	  DW	SETHELP
	  DB	'ORI','G'+80H		; originate mode
	  DW	ORIG
	  DB	'ANSWE','R'+80H		; answer mode
	  DW	ANS
	  DB	'TON','E'+80H		; tone dialing
	  DW	STTONE
	  DB	'PULS','E'+80H		; pulse dialing
	  DW	STPULSE
	  DB	'MONITO','R'+80H	; monitor on
	  DW	MONIT
	  DB	'QUIE','T'+80H		; monitor off
	  DW	QUIET
	  DB	'BAU','D'+80H		; set baud
	  DW	STBAUD
	  DB	'DELA','Y'+80H		; set delay
	  DW	DELAY
	  DB	'PARIT','Y'+80H		; set parity
	  DW	STPRTY
	  DB	'STO','P'+80H		; set stopbits
	  DW    STSTOP
	  DB	'BIT','S'+80H		; set length
	  DW	STBITS
	  DB	'DIGI','T'+80H		; set inter-digit delay
	  DW    SDIGIT
	  DB	0			;table terminator
;
;  "set (no args): print current statistics
;
SETSHO:	  CALL  MILP
	  DB	CR,LF
	  DB	'Current settings:',CR,LF,0
	  CALL	CRLF
	  CALL	TPSHOW
	  CALL	CRLF
	  CALL	BDSHOW
	  CALL  CRLF
	  CALL	MONSHO
	  CALL	CRLF
	  CALL  SHOWP
	  CALL	CRLF
	  CALL	SHOWS
	  CALL	CRLF
	  CALL  SHOWBT
	  CALL  CRLF
	  CALL	DLSHOW
	  CALL	CRLF
	  CALL	DDSHOW
	  CALL  CRLF
	  CALL  CRLF
	  RET
;
; "set ?" processor
;
SETHELP:  CALL	MILP
	  DB	CR,LF,'SET ORIG      - Modem Originate mode'
	  DB	CR,LF,'SET ANSWER    - Modem Answer mode'
	  DB	CR,LF,'SET TONE      - Touch Tone dial'
	  DB	CR,LF,'SET PULSE     - Dial Pulse dial'
	  DB	CR,LF,'SET PARITY    - None, Even or Odd'
	  DB	CR,LF,'SET STOP      - 1, 1.5 or 2'
	  DB	CR,LF,'SET BITS      - 5, 6, 7 or 8'
	  DB	CR,LF,'SET QUIET     - Speaker Off'
	  DB	CR,LF,'SET MONITOR   - Speaker On'
	  DB	CR,LF,'SET BAUD <X>  - <X> = 110, 300, 600, 1200, 2400, '
	  DB	'4800, 9600, 19200'
	  DB	CR,LF,'SET DELAY <X> - <X> seconds'
	  DB	CR,LF,'SET DIGIT <X> - <X> 0-99 mS'	
	  DB	CR,LF,CR,LF,0
	  RET
;
; "set baud" processor
;
STBAUD:	  	MVI	C,BDPARS	;function code: parse a baudrate
	  	CALL	MEX		;let mex look up code
	  	JC	SETERR		;jump if invalid code
	  	CALL	PBAUD		;no, try to set it
	  	JC	SETERR		;if not one of ours, bomb out
;
; let MEX print the baud rate
;
BDSHOW:	  	LDA	MSPEED		;get current baud rate
	  	MVI	C,PRBAUD	;let mex print it
	  	CALL	MEX
	  	RET 
;
; this routine sets baud rate passed as mspeed code in a.
; returns cy=1 if baud rate not supported.
;
PBAUD:	  	PUSH	H		;don't alter anyboby
	  	PUSH	D
	  	PUSH 	B
;
		LXI	H,BAUDS		; get the table base
		MOV	E,A
		MVI	D,00
		DAD	D		; offset it
		MOV	A,M
		CPI	11111111B	; is it bad ?
		STC
		JZ	BADEX		; yup - quit now
;
; selected rate is good ... save parameters
;
		STA	DFTBAUD		; setup for reinitialization
		MOV	A,E
		STA	SPEED		; save it in case of CLONE command
		STA	MSPEED
		CALL	SINITL		; reinitialize the usart
		STC		
		CMC			; no error here
BADEX:		POP	B
	  	POP	D
	  	POP	H
		RET
;
; lookup table for all of the valid bit rates 
;
BAUDS:		DB	00000010B	; 110 baud
		DB	00000101B	; 300 baud
		DB	11111111B	; 450 baud	
		DB	00000110B	; 600 baud
		DB	11111111B	; 710 baud
		DB	00000111B	; 1200 baud
		DB	00001010B	; 2400 baud
		DB	00001100B	; 4800 baud
		DB	00001110B	; 9600 baud
		DB	00001111B	; 19.2k baud
;
; "set mode" processor
;
ORIG:	XRA	A
	STA	ANSFLG		;set orig flag
	LXI	H,SMO		;send out ats0=0
	CALL	SINIT
	CALL	MILP
	DB	'Originate mode',0
	RET
;
ANS:	MVI	A,0FFH
	STA	ANSFLG		;set ans flag
	LXI	H,SMA		;send out ats0=1
	CALL	SINIT
	CALL	MILP
	DB	'Answer mode',0
	RET
;
SMO:	DB	'ATS0=0',CR,0
SMA:	DB	'ATS0=1',CR,0
;
;
; "monitor" processor
;
QUIET:	XRA	A
	STA	MONFLG
	LXI	H,SMQT
	CALL	SINIT
	JMP	MONSHO

MONIT:	MVI	A,0FFH
	STA	MONFLG
	LXI	H,SMMON
	CALL	SINIT

MONSHO:	LDA	MONFLG
	ORA	A
	JZ	MONOFF
	CALL	MILP
	DB	'Speaker On',0
	RET

MONOFF:	CALL	MILP
	DB	'Speaker Off',0
	RET

SMQT:	DB	'ATM0',CR,0
SMMON:	DB	'ATM1',CR,0
;
; "dial" processor
;
STTONE:	MVI	B,'T'
	JMP	SDIAL1
STPULSE:MVI	B,'P'

SDIAL1: LDA	TPULSE
	CPI	B
	JZ	TPSHOW
	MOV	A,B
	STA	TPULSE
	CPI	'P'
	MVI	A,01010000B	;pulse dial
	JZ	SDIAL2
	MVI	A,01000000B	;tone dial
SDIAL2: STA	DIALWD

TPSHOW:	LDA	DIALWD
	ANI	00010000B
	JZ	TPTONE

	CALL	MILP
	DB	'Pulse Dial',0
	RET

TPTONE:	CALL	MILP
	DB	'Tone Dial',0	  
	RET
;
; "delay" processor
;
DELAY:	MVI	C,EVALA
	CALL	MEX
	MOV	A,H
	ORA	A
	JNZ	SETERR
	MOV	A,L
	CPI	100		;too big ?
	JNC	SETERR

	PUSH	D		; convert binary to ascii
	CALL	CVDCML
	MOV	A,D
	STA	S7NIT+3		; 10's digit
	STA	LDSTR+5
	MOV	A,E
	STA	S7NIT+4		; 1's digit
	STA	LDSTR+6
	POP	D

	LXI	H,LDSTR		; send the local string to the modem
	CALL	SMSEND

DLSHOW:	CALL	MILP		;finally tell the user about it
	DB	'Answer delay is ',0
;
	LDA	S7NIT+3		;print 10'S DIGIT
	MOV	E,A	
	MVI	C,CONOUT
	CALL	MEX
;
	LDA	S7NIT+4		;print 1'S DIGIT
	MOV	E,A	
	MVI	C,CONOUT	
	CALL	MEX
;
	CALL	MILP		;print units
	DB	' Seconds.',0
	RET

LDSTR:	DB	'ATS7=30',CR,0

;
; "digit" processor - interdigit time 
 
SDIGIT:	MVI	C,EVALA
	CALL	MEX
	MOV	A,H
	ORA	A
	JNZ	SETERR
	MOV	A,L
	CPI	100		;too big ?
	JNC	SETERR
;
	PUSH	D		; convert binary to ascii
	CALL	CVDCML
	MOV	A,D
	STA	S11NIT+4	; 10's digit
	STA	LSTR+6
	MOV	A,E
	STA	S11NIT+5	; 1's digit
	STA	LSTR+7
	POP	D
;
	LXI	H,LSTR		; send the local string to the modem
	CALL	SMSEND

DDSHOW:	CALL	MILP		;finally tell the user about it
	DB	'Dial digit time is ',0
;
	LDA	S11NIT+4		;print 10'S DIGIT
	MOV	E,A	
	MVI	C,CONOUT
	CALL	MEX
;
	LDA	S11NIT+5		;print 1'S DIGIT
	MOV	E,A	
	MVI	C,CONOUT	
	CALL	MEX
;
	CALL	MILP		;print units
	DB	' Ms.',0
	RET

LSTR:	DB	'ATS11=40',CR,0
;
; convert to ascii the hard way
;
CVDCML:	MVI	B,0		; make ascii out of 7 bit binary 
TENS:	SUI	10
	JC	ONES		; gone negative yet ?
	INR	B
	JMP	TENS		; nope... keep bumping the 10'S DIGIT
;
ONES:	ADI	10		; fix it
	PUSH	PSW		; save the number for a sec
	MOV	A,B
	ADI	'0'		; add in the ascii bias
	MOV	D,A
	POP	PSW
 	ADI	'0'		; add in the ascii bias - must be 0-9
	MOV	E,A
	RET

;
;	set parity command: reset transmit/receive parity
;
;		parity is controlled by bits 4 and 5 of mode register 1
;		for the 2651 
;
;		   parity	bit 5	   bit 4
;	             off          -          0
;	 	     odd	  0	     1
;		     even	  1	     1
;
STPRTY:	MVI	C,SBLANK	;check for parity code
	CALL	MEX		;
	JC	SETERR		;if none, print error
	LXI	D,PARTBL	;check for proper syntax
	MVI	C,LOOKUP
	CALL	MEX
	PUSH	H		;match found, go do it!
	RNC			;
	POP	H		;no match: fix stack and
	JMP	SETERR		;  print error
;
PROFF:	MVI	A,00000000B
	STA	DFTPAR
	JMP	SHOWP1

PREVEN:	MVI	A,00110000B
	STA	DFTPAR
	JMP	SHOWP1

PRODD:	MVI	A,00010000B
	STA	DFTPAR

SHOWP1:	CALL	SINITL

SHOWP:	LDA	DFTPAR
	RRC
	RRC	
	RRC
	RRC
	ANI	00000011B
	ADD	A
	MOV	E,A
	MVI	D,00
	PUSH	D
	CALL	MILP		;display parity
	DB	'Parity is ',0
	POP	D
	LXI	H,PVECT
	DAD	D
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	PCHL

PVECT:	DW	OFFMSG
	DW	ODDMSG
	DW	OFFMSG		
	DW	EVNMSG
	
OFFMSG:	CALL	MILP		;
	DB	'(None)',0	;
	RET

ODDMSG:	CALL	MILP		;
	DB	'Odd',0		;
	RET			;

EVNMSG:	CALL	MILP		;
	DB	'Even',0	;
	RET
;
;	set parity command table
;
PARTBL:	  DB	'NON','E'+80H	;"set parity off"
	  DW	PROFF
	  DB	'EVE','N'+80H	;"set parity even"
	  DW	PREVEN
	  DB	'OD','D'+80H	;"set parity odd"
	  DW	PRODD
	  DB	0		;<<== end of parity table
;
;	set stopbits command: reset number of stop bits
;
;		the stop bits are controlled by bits 7 and 8 of mode register 
;		1 for the 2651 
;
;		    stop bits	   bit 7	bit 8
;			1	     0            1
;		       1.5	     1		  0
;			2	     1		  1
;
;
STSTOP:	  MVI	C,SBLANK	;check for stop bits
	  CALL	MEX
	  JC	SETERR		;if none, print error
	  LXI	D,STPTBL	;check syntax
	  MVI   C,LOOKUP
	  CALL	MEX
	  PUSH	H		;match found, go do it!
	  RNC	
	  POP	H		;no match: fix stack and
	  JMP	SETERR		;print error
;
STOP01:	MVI	A,01000000B	; 1 stop bit
	STA	DFTSTP
	JMP	SHOWS
;
STOP02:	MVI	A,11000000B	; 2 stop bits
	STA	DFTSTP
	JMP	SHOWS
;
STOP15:	MVI	A,10000000B	; 1 1/2 stop bits
	STA	DFTSTP
;
SHOWS:	LDA	DFTSTP		; print the current setting
	RRC
	RRC
	RRC
	RRC
	RRC
	RRC
	ANI	00000011B	; mask any possible crap	
	ADD	A		; <a> * 2
	MOV	E,A
	MVI	D,00
	PUSH	D
	CALL	SINITL		; reinit the usart
	CALL	MILP
	DB	'There ',0
	POP	D
	LXI	H,SVECT
	DAD	D
	MOV	A,M		; dispatch
	INX	H
	MOV	H,M
	MOV	L,A
	PCHL

SVECT:	DW	MSG0
	DW	MSG1
	DW	MSG15
	DW	MSG2

MSG0:	CALL	MILP
	DB	'is an INVALID MODE COMMAND - UNKNOWN ERROR in MEX'
	DB	DING,CR,LF,0
	RET

MSG1:	CALL	MILP		; display '1'	
	DB	'is 1 stop bit',0		;
	RET

MSG2:	 CALL	MILP		; display '2' 
	 DB	'are 2 stop bits',0		;
	 RET

MSG15:	CALL	MILP		; display '1.5'
	DB	'are 1.5 stop bits',0
	RET

;	set stopbits command table
;
STPTBL:	  DB	'1'+80H		;"set stop 1"
	  DW	STOP01
	  DB	'2'+80H		;"set stop 2"
	  DW	STOP02
	  DB	'1.','5'+80H	;"set stop 1.5"
	  DW	STOP15
	  DB	0		;<<== end of stop-bits table
;
;	set length command: set bits per character
;
;		the number of bits per character is controlled by 
;		bits 3 and 2 of mode register 1 for the 2651
;		3 only, but are the same for register 5:
;
;		    bpc		bit 3		bit 2
;		     5		  0		  0
;		     6		  0   		  1
;		     7		  1		  0
;		     8		  1		  1
;
STBITS:	  MVI	C,SBLANK	;check for bits/char
	  CALL	MEX
	  JC	SETERR		;if none, print error
	  LXI	D,BITTBL	;check syntax
	  MVI	C,LOOKUP
	  CALL	MEX
	  PUSH	H		;match found, go do it!
	  RNC	
	  POP	H		;no match: fix stack and
	  JMP	SETERR		;print error
;
BIT5:	MVI	A,00000000B
	STA	DFTBITS
	JMP	SHOWBT

BIT6:	MVI	A,00000100B
	STA	DFTBITS
	JMP	SHOWBT

BIT7:	MVI	A,00001000B
	STA	DFTBITS
	JMP	SHOWBT

BIT8:	MVI	A,00001100B
	STA	DFTBITS

SHOWBT:	LDA	DFTBITS		; get default setting
	RRC
	RRC
	ANI	00000011B	; mask garbage if any
	ADD	A		; <a> * 2
	MOV	E,A
	MVI	D,00
	PUSH	D
	CALL	SINITL		; reinit the usart
	CALL	MILP
	DB	'There are ',0
	POP	D
	LXI	H,BVECT
	DAD	D
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	PCHL

BVECT:	DW	BITS5
	DW	BITS6
	DW	BITS7
	DW	BITS8

BITS5:	  CALL	MILP		; display '5'
	  DB	'5 bits/char',0		
	  RET			
BITS6:	  CALL	MILP		; display '6'
	  DB	'6 bits/char',0		
	  RET			
BITS7:	  CALL	MILP		; display '7'
	  DB	'7 bits/char',0		
	  RET			
BITS8:	  CALL	MILP		; display '8'
	  DB	'8 bits/char',0		
	  RET			
;
;	set length command table
;
BITTBL:	  DB	'5'+80H		;"set bits 5"
	  DW	BIT5
	  DB	'6'+80H		;"set bits 6"
	  DW	BIT6
	  DB	'7'+80H		;"set bits 7"
	  DW	BIT7
	  DB	'8'+80H		;"set bits 8"
	  DW	BIT8
	  DB	0		;<<== end of bpc table
;
;
; build the default initialization from ram so as to be cloneable
;
SINITL:	IN	CPORT		; reset the mode registers	
	LDA	DFTSTP		; get default stop bits
	MOV	B,A
	LDA	DFTPAR		; get default parity
	ORA	B
	MOV	B,A
	LDA	DFTBITS		; get default character length
	ORA	B
	ORI	00000010B	; force divide by 16 - use internal baud gen
	OUT	MODE1		; set the register

	LDA	DFTBAUD		; get the default baud rate
	ORI	00110000B	; force internal clocks
	OUT	MODE2		; set the register

	MVI	A,00100111B	; force dtr, cts, async, txe, rxe, no loopbak
	OUT 	CPORT
	RET
;
;
; smartmodem dialing routine ... by a "cast of thousands"
;
DIAL:	  LHLD	DIALPT		;fetch pointer
	  CPI	254		;start dial?
	  JZ	STDIAL1		;jump if so
	  CPI	255		;end dial?
	  JZ	ENDIAL1		;jump if so
;
; not start or end sequence, must be a digit to be sent to the modem
;
	  MOV	M,A		;put char in buffer
	  INX	H		;advance pointer
	  SHLD	DIALPT		;stuff pntr
	  RET			;all done
;
; here on a start-dial sequence
;
STDIAL1:  LXI	H,DIALBF	;set up buffer pointer
	  SHLD	DIALPT
	  RET
;
; here on an end-dial sequence
;
ENDIAL1:  MVI	M,CR		;stuff end-of-line into buffer
	  INX	H		;followed by terminator
	  MVI	M,0
	  LDA	TPULSE		;get overlay'S TOUCH-TONE FLAG
	  STA	SMDIAL+3	;put into string
	  LXI	H,SMDIAL	;point to dialing string
	  CALL	SMSEND		;send it
WAITSM:	  MVI	C,INMDM
	  CALL	MEX		;catch any output from the modem
	  JNC	WAITSM		;loop until no more characters
;
; the following loop waits for a result from the modem.
;
RESULT:	  MVI	A,60		; dont hang longer than a minute
	  MOV	C,A

SMWLP:	  PUSH	B
	  MVI	B,1		;check for a char, up to 1 sec wait
	  MVI	C,TMDINP	;do timed input
	  CALL	MEX
	  POP	B
	  JNC	SMTEST		;jump if modem had a char
	  PUSH	B		;no, test for control-c from console
	  MVI	C,CHEKCC
	  CALL	MEX
	  POP	B
	  JNZ	SMNEXT		;if not, jump
	  CALL	SMDMOFF		;yes, shut down the modem
	  MVI	A,3		;return abort code
	  RET
SMNEXT:	  DCR	C		;no
	  JNZ	SMWLP		;continue
;
; no modem response within the time specified in set delay command
;
SMTIMO:	CALL	SMDMOFF
	MVI	A,2		;return timeout code
	RET
;
; modem gave us a result, check it
;
SMTEST:	  ANI	7FH		;ignore any parity
	  CALL	SMANAL		;test the result
	  JC	RESULT		;go try again if unknown response
	  MOV	A,B		;a=result 
	  PUSH	PSW		;save it
SMTLP:	  MVI	C,INMDM		;eat any additional chars from smartmodem
	  CALL	MEX
	  JNC	SMTLP		;until 100ms of quiet time
	  POP	PSW		;return the code
	  RET
;
; analyze character returned from modem
;
SMANAL:	  MVI	B,0		;prep connect code
	  CPI	'C'		;"connect"?
	  RZ
	  CPI	'1'		;numeric version of "connect"
	  RZ
	  CPI	'5'		;numeric version of "connect 1200"
	  RZ
	  INR	B		;prep busy code b=1
	  CPI	'B'
	  RZ
	  INR	B		;prep no connect msg b=2
	  CPI	'N'		;n=no connect
	  RZ
	  CPI	'3'		;numeric version of "no connect"
	  RZ
	  MVI	B,4		;prep modem error
	  CPI	'E'		;e=error
	  RZ
	  CPI	'4'		;numeric version of "error"
	  RZ
;
; unknown response, return carry to caller. but first,
; flush the unknown response line from the modem.
;
WTLF:	  CPI	LF		;linefeed?
	  STC
	  RZ			;end if so
	  MVI	C,INMDM		;no. get next char
	  CALL	MEX
	  JNC	WTLF		;unless busy, loop
	  RET
;
; send string to the external modem
;
SMSEND:	  MVI	C,SNDRDY	;wait for modem ready
	  CALL	MEX
	  JNZ	SMSEND
	  MOV	A,M		;fetch next character
	  INX	H
	  ORA	A		;end?
	  RZ			;done if so
	  MOV	B,A		;no, position for sending
	  MVI	C,SNDCHR	;nope, send the character
	  CALL	MEX
	  JMP	SMSEND
;
; disconnect smodem - if DTR didnt, this will...
;
SMDMOFF:  MVI	B,CR
	  MVI	C,SNDCHR
	  CALL	MEX
	  MVI	B,10		;one second wait for hayes, etc
     	  CALL	MTIME
	  JMP	DISCON		;make sure it is off
;
; general utility routines
;
MILP:	  MVI	C,ILP		;in-line print
	  JMP	MEX
	  RET
;
MTIME:	  MVI	C,TIMER		; mex timer
	  JMP	MEX
	  RET
;
CRLF:	  CALL	MILP		; print carriage return, line feed
	  DB	CR,LF,0
	  RET

DONEW:	  PUSH	H		; save the new command string fro a sec 
	  LXI	H,ATNSTR
	  CALL	SMSEND		; wake up the modem with 'AT'
	  POP	H
	  JMP	SINIT		; now send the new parameter

ATNSTR:	  DB	'AT',0
;
;==========================================================================
;                            data area
;==========================================================================
;
; default uart parameters 
;
DFTSTP:	   DB	 01000000B	; default stop bits - 1
DFTPAR:	   DB	 00000000B	; default parity - none
DFTBITS:   DB	 00001100B	; default character length - 8 bits
DFTBAUD:   DB    00000000B	; default baud rate scratch area 
;
SMDIAL:	  DB	'ATDT '		; smartmodem dial prefix
DIALBF:	  DS	52		; 2* 24 char max, + cr + null + slop
DIALPT:	  DS	2		; dial position pointer
DIALWD:	  DB	01000000B	; pulse/tone dial word
DIGIT	  DB	0		; save dialed digit
SPEED:	  DB	5		; default baud rate 
				; 0=110,1=300,3=600,5=1200,6=2400
				; 7=4800,8=9600,9=19200 
MONFLG:	  DB	0FFH		; 0: monitor off - 0ffh: monitor on
ANSFLG:	  DB	0		; 0: originate   - 0ffh: ans
;
SMATN:    DB	'+++',0		; smartmodem online 'ATTENTION'
SMDISC:	  DB	'ATH',CR,0	; smartmodem disconnect 
SMINIT:   DB	'ATM1 '		; speaker
S0NIT:	  DB	'S0=0 '		; answer ring counter
S7NIT:	  DB	'S7=30'		; carrier wait delay seconds
XNIT:	  DB	'X1'		; result code mode 
S11NIT:	  DB	'S11=40 '	; interdigit delay in ms
	  DB	CR,0		; modem init string

;
;******************************************************************************
;
				  END
;
;******************************************************************************

