.title DTE_HAYES SET HOST/DTE dialler for Hayes "AT" modems ;++ ; ; DTE_HAYES -- Hayes compatible dialler module for SET HOST/DTE ; ; This module allows a modem that understands the Hayes "AT" command set ; to be used with SET HOST/DTE/DIAL. ; ; To set up, compile and link as follows: ; ; $ MACRO DTE_HAYES ; $ LINK/SHARE DTE_HAYES ; ; To use, place DTE_HAYES.EXE into SYS$SHARE: and issue the command: ; ; $ SET HOST/DTE modem/DIAL=(MODEM_TYPE=HAYES,NUMBER=number) ; ; Alternatively, assign the logical DTE_DF03 to point to DTE_HAYES (it doesn't ; need to be in SYS$SHARE:) and just use SET HOST/DTE/DIAL=number, eg: ; ; $ ASSIGN SYS$LOGIN:DTE_HAYES DTE_DF03 ; $ SET HOST/DTE modem/DIAL=NUMBER=number ; ; (This works because DTE_DF03 is the default dialler module loaded if the ; MODEM_TYPE keyword is left off SET HOST/DTE.) If you don't have any ; DF03s, you may wish to assign the logical systemwide. ; ; ; ; Don Stokes 30-Oct-1991 ; Network manager, ; Computer Services Centre, Email: don@vuw.ac.nz ; Victoria University of Wellington, Home: don@zl2tnm.gen.nz ; New Zealand. Phone: +64 4 495-5052 ; ; No warranty or support of any kind is expressed or implied, but bugfixes, ; suggestions or job offers are always welcome. Copyright remains with the ; author. ; ; Modifications to display modem response, rather than expect item, by ; John Rumsey 24 Jan 1994 ; Quorum Computing Ltd Email: john@quorum.co.nz ; PO Box 14171 Phone: +64 4 387 2827 ; Kilbirnie 6041 ; New Zealand ; ;-- .sbttl Macros and things $STSDEF $SHRDEF ; ; CALL macro - call a subroutine, pass parameters on stack ; Usage: CALL routine [,p1...,p20] ; .macro call routine, - p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11, - p12,p13,p14,p15,p16,p17,p18,p19,p20 .narg call.argc call.argc = call.argc - 1 call.argn = 20 .irp call.argv, .if less_equal call.argn - call.argc pushal call.argv .endc call.argn = call.argn - 1 .endr calls #call.argc, G^routine .endm ; ; Status macro. ; Every good MACRO program has one of these; this is no exception. ; .macro status, cond, ?L1 blbs cond, L1 $EXIT_S cond L1: .endm .sbttl Data areas .psect DTE_RW, long,noexe,wrt,noshr ; ; Workings: ; iosb: .blkw 4 ; Dogsbody iosb waittime: .blkl ; Temp storage for WAIT buflen = 80 ; Buffer for modem responses bufdsc: .long buflen .address buffer+1 buffer: .blkb buflen timeout: .ascid "Timed out" ; Time out message rem$_facility = ^X1FE ; REM-?-TEXT, message rem$_text = SHR$_TEXT! ; ; Script stuff ; cr = 13 send_init: .ascid "ATQ0" send_dial: .ascid "ATDT" send_cr: .ascid send_reset: .ascid "ATZ" ; Lists of possible responses by the modem. The first in the list is the ; successful case; remaining responses indicate some sort of failure. ; The list is terminated by a zero byte (effectively an ascic null string). init_expects: .ascic "OK" ; Success condition .ascic "ERROR" ; Failure conditions .ascic "RING" .byte 0 ; terminate list dial_expects: .ascic "CONNECT" ; Success .ascic "BUSY" ; Failure conditions .ascic "ERROR" .ascic "NO ANSWER" .ascic "NO CARRIER" .ascic "NO DIALTONE" .ascic "RING" ; Avoid confusion with RINGING .ascic "VOICE" .byte 0 ; terminate list .sbttl Linkage ; ; Linkage code ; .psect DTE_RE, long,exe,nowrt,shr .transfer DIAL_ROUTINE .mask DIAL_ROUTINE brb DIAL_ROUTINE+2 .sbttl Mainline ; ; Main routine ; 4(AP) = Dial string ; 8(AP) = channel to modem ;12(AP) = channel to terminal ; .entry DIAL_ROUTINE,^m<> ; ; Initialise modem ; call wait @#1000 ; Let modem settle from shock call flush @8(AP) ; of being asked to do something call send @8(AP), send_init ; Initialise modem call expect, @8(AP), init_expects, @#5 blbc R0, failed ; ; Dial number ; call wait @#2000 ; Let modem recover from init call send @8(AP), send_dial ; Send ATDT call send @8(AP), @4(AP) ; Send phone call send @8(AP), send_cr ; Send cr call expect, @8(AP), dial_expects, @#60 blbc R0, failed ; ; Connected. Display connect message and hand control back to DTEPAD. ; call LIB$SIGNAL @#rem$_text!STS$K_SUCCESS, @#1, bufdsc movl #SS$_NORMAL, R0 ; TA DA! ret ; ; Report status and die. R1 = reason. ; failed: call LIB$SIGNAL @#rem$_text!STS$K_ERROR, @#1, bufdsc movl #rem$_text!STS$M_INHIB_MSG!STS$K_ERROR, R0 ret .sbttl Routine to send characters to the modem ; ; SEND chan, string ; ; Sends one character at a time to modem. ; .entry send, ^m movl 8(AP), R0 ; R0 = descriptor addr movl 4(R0), R2 ; R2 = pointer cvtwl (R0), R3 ; R3 = counter 1$: $QIOW_S chan=4(AP), iosb=iosb, - func=#IO$_WRITEVBLK!IO$M_NOFORMAT, - p1=(R2), p2=#1 status R0 status iosb call wait @#100 status R0 incl R2 decl R3 bneq 1$ ret .sbttl Routine to flush the typeahead buffer ; ; FLUSH channel ; ; Flushes the typeahead ; .entry flush, ^m<> 1$: $QIOW_S chan=4(AP), iosb=iosb, - func=#IO$_READVBLK!IO$M_PURGE!IO$M_TIMED,- p1=buffer, p2=#0, p3=#0 status R0 ret .sbttl Routine to read characters and match expected strings ; ; EXPECT chan, expect_address, timeout ; ; Expects strings to come in through the port. expect_address is a pointer ; to a series of counted strings, terminated by a null string. ; On exit, R0 is 1 if the first expect string matched (success), or zero ; if another expect string matched or the read timed out. ; .entry expect, ^m ; ; Read modem response string (note CR is terminator, but LF isn't). ; 1$: $QIOW_S chan=4(AP), iosb=iosb, - func=#IO$_READVBLK!IO$M_TIMED!IO$M_NOECHO, - p1=buffer, p2=#buflen, p3=12(AP) status R0 ; ; Exit if timeout ; cmpw iosb, #SS$_TIMEOUT bneq 3$ movq timeout, bufdsc ; timeout message clrl R0 ; R0 = 0 ret 2$: brb 1$ ; helper branch 3$: status iosb ; ; Search expect list for string in expect buffer ; addw3 iosb+2, iosb+6, R6 ; R6 = length of modem response decw R6 ; less leading line feed movab buffer+1, R7 ; R7 = address of modem response subw3 #1, iosb+2, bufdsc ; Store these in BUFDSC movl 8(AP), R9 ; R9 = address of expect list movl #1, R10 ; R10 = initial status (succ) 4$: movzbl (R9)+, R8 ; R8 = length of expect item beql 2$ ; Zero = list end. Read next. cmpw R6, R8 ; Response as long as item? blss 5$ ; No: try next item cmpc R8, (R7), (R9) ; Do strings match? bneq 5$ ; No: try next item movl R10, R0 ; A real match. Return status. ret 5$: addl2 R8, R9 ; point R9 at next expect item clrl R10 ; set status to failure brb 4$ ; try next item .sbttl Routine to wait for a period of time ; ; WAIT milliseconds ; .entry wait, ^m<> cvtlf 4(AP), R0 mulf3 #0.001, R0, waittime call LIB$WAIT waittime ret .end